正确重写equals方法和compareTo方法

Posted suen061

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正确重写equals方法和compareTo方法相关的知识,希望对你有一定的参考价值。


一、概述


程序要对一堆数据元素排序,查找,增加删除。
数据节点

class Node{
        int type;
        int index;
        int score;
}

  

规则:
  1)对象相等:两个节点n1与n2,如果n1.type == n2.type && n1.index == n2.index则n1等于n2
  2)排序:升序,比较score,score相同则比较type,type相同则比较index.
最开始我使用TreeMap存储。实现Comparable接口,重写equals方法与hashCode方法。
如下:

class Node implements Comparable<Node>{
	public int type;
	public int index;
	public int score;
	public Node(int t, int u, int s) {
		this.type = t;
		this.index = u;
		this.score = s;
	}
	@Override
	public int compareTo(Node o) {
		if(this.score != o.score) return this.score > o.score ? -1 : 1;
		else if(this.type != o.type) return this.type - o.type;
		else return this.index - o.index;
	}
	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if(this == obj) return true;
		if(obj instanceof Node) {
			Node tn = (Node) obj;
			if(tn.type == this.type && tn.index == this.index) return true;
		}
		return false;
	}
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.type + this.index;
	}
}

程序一直不对,经过两个小时反复的检查。我意识到,TreeMap比较对象是否相同也是调用CompareTo方法。equals和hashCode是HashMap那一套。
修改后,每个type的数据用一个TreeMap保存。
如下:

class Node implements Comparable<Node>{
	public int type;
	public int index;
	public int score;
	public Node(int t, int u, int s) {
		this.type = t;
		this.index = u;
		this.score = s;
	}
	@Override
	public int compareTo(Node o) {
		if(this.type == o.type && this.index == o.index) return 0;
		else {
			if(this.score != o.score) return this.score > o.score ? -1 : 1;
			else return this.index - o.index;
		}
	}
}

最后的排序使用优先队列。
比较器:

Comparetor<Node> cmp = (x, y) ->{
	if(x.score != y.score) return x.score > y.score ? -1: 1;
	else if(x.type != y.type) return x.type - y.type;
	return x.index - y.index;
}

正确使用equals和compareTo,减少bug。


二、重写equals


HashSet中存储自己定义的对象,HashMap使用自定义的对象作Key,都需要重写equals。同时要重写hashCode.
hashCode定位,equals比较对象是否相同。
如下:

@Override
public boolean equals(Object obj) {//参数类型必须为Object,否则无效
	// TODO Auto-generated method stub
	if(this == obj) return true; //同引用
	if(obj instanceof Node) {//obj为null时,条件为假。
		Node tn = (Node) obj;
		if(tn.type == this.type && tn.index == this.index) return true;//根据内容比较对象
	}
	return false;
}

hashCode方法要保证相同对象的返回值相同。想实现一个好的hashCode比较难。


三、重写compareTo


有序的集合,存储自定以的对象都需要重写compareTo方法或者提供该对象的比较器。常用到的集合有TreeMap(红黑树)、TreeSet、PriorityQueue(堆)、Arrays::sort(数组排序)、Collections::sort(List排序)。
如下:

class Data implements Comparable<Data>{ //实现Comparable接口
	@Override
	public int compareTo(Data o) {//小于返回负值,等于返回0,大于返回正值
		// TODO Auto-generated method stub
		return 0;
	}
}

比较器,如下:

Comparator<Node> cmp = new Comparator<Node>() {
		@Override
		public int compare(Node o1, Node o2) {
			// TODO Auto-generated method stub
			return 0;
		}
	};


使用Lambda表达式。

Comparetor<Node> cmp = (x, y) ->{
	if(x.score != y.score) return x.score > y.score ? -1: 1;
	else if(x.type != y.type) return x.type - y.type;
	return x.index - y.index;
}

以上是关于正确重写equals方法和compareTo方法的主要内容,如果未能解决你的问题,请参考以下文章

为啥要重写toString方法和hashcode方法

如何正确的重写equals() 和 hashCode()方法

JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法

Java比较学习重写equals方法的安全写法

Java 中 equals 和 == 的区别

java的comparable接口啥意思