1.“==”,”equals()”,”hashCode()”等的问题

原创
02/22 17:33
阅读数 4K

“==”,”equals()”,”hashCode()”这三个是不同而又有密切联系的概念,下面会梳理相关的知识点进行辨析。

一、==是运算符,equals()和hashCode()是函数

二、==”操作符的用法

#1.如果==的两边都是基本类型变量、包装类对象所组成的表达式,==用于比较两边的表达式的值是否相等——只要两边的表达式的值相等,即使数据类不同,该运算符也会返回true。例如'a' == 97.0,将会返回 true。

#2如果==的两边是引用类型的变量,==用于判断这两个引用类型的变量是否引用同一块内存,只有当它们引用同一块内存时,==才会返回 true。

三、”equals()”函数的用法

    equals()则是一个 java.lang.Object 类的一个方法,因此任何 Java 对象都可调用该方法 与其他对象进行比较。java.lang.Object 类的 equals 方法的实现代码如下:

	boolean equals(Object o) {
		return this == o;
	}

从上面代码可以看出,如果一个类没有重写 java.lang.Object 的 equals()方法时,此时 equals()方法的比较结果与==的比较结果是相同的

Java 允许任何类重写 equals()方法,重写该方法就是让程序员来自己决定两个对象相 等的标准——极端的情况下,我们完全可以设计出 Person 对象与 Dog 对象 equals()比较返回 true 的情况——当然一般不会这么设计。

实际上重写 equals()方法时通常会按如下格式:

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (pass == null) {
			if (other.pass != null)
				return false;
		} else if (!pass.equals(other.pass))
			return false;
		return true;
	}

上面重写 equals()方法用于判断两个 Person 对象是否“相等”,程序只要两个 Person 对 象的 namepass 相等,程序就可以把这两个 Person 对象当成相等——这是系统业务决定的。

如果业务需要,我们也可以增加更多的参与判断的 Field,当然也可以只根据 name 进行判断 ——只要两个 Person name 相等,就认为两个 Person 相等,这都是由系统的业务决定。

总结起来就是一句话:开发者重写 equals()方法就可以根据业务要求来决定两个对象是 否“相等”

四、”equals()”和“hashCode()”的不同作用

hashCode()方法与 equals()方法相似,都是来自 java.lang.Object 类的方法,都允许用户定义的子类重写这两个方法。

一般来说,equals()这个方法是给用户调用的,如果你想根据自己的业务规则来判断两个对象是否相等,你可以重写 equals()方法。简单来讲,equals 方法主要是用来判断从表面上看或者从内容上看,两个对象是不是相等

而 hashCode()方法通常是给其他类来调用的,比如当我们要把两个对象放入 HashSet 时由于 HashSet 要求两个对象不能相等,HashSet 判断两个对象是否相等的标准是通过equals()比较返回 false、或两个对象的 hashCode()方法返回值不相等——只要满足任意一个 条件都可会认为两个对象不相等

从这个角度来看,我们可以把 hashCode()方法的返回值当成这个对象的“标识符”,如果两个对象的 hashCode()相等,即可认为这两个对象是相等的。因此当我们重写一个类的 equals()方法时,也应该重写它的 hashCode()方法,而且这两个方法判断两个对象相等的标 准也应该是一样的

比如两个对象值相同(x.equals(y) == true),但却可以有不同的 hashCode因为 equals()方法可以由开发者重写,hashCode()方法也可以由开发者来重写,因此它们是否相等并没有必然的关系

五、Set中重复元素的判断

Set 只是一个接口,它的不同实现类判断元素是否相等的标准是不同的。笼统地说,Set 里的元素是不能重复的,判断元素重复。

对于 HashSet 而言,判断两个对象是否相等是通过 equals()和 hashCode()方法,只要两个对象通过 equals()比较返回 false、或两个对象的 hashCode()不相等,那么 HashSet 就会把它们当成不相同。

对于TreeSet而言,判断两个对象相等的唯一标准是:两个对象通过compareTo(Object obj)比较是否返回 0,与 equals()方法无关。只要两个对象通过 compareTo(Object obj)比较没有返回 0,Java 就会把它们当成两个对象处理——这一点是很多人容易误解的,不过我们可以通的一个示例来说明:

class Z implements Comparable {
	int age;

	public Z(int age) {
		this.age = age;
	}


	// 重写 equals()方法,总是返回 true
	public boolean equals(Object obj) {
		return true;
	}

	// 重写 hashCode()方法,总是返回 1
	public int hashCode() {
        int h = 1;
        return h;
    }
	
	// 重写了 compareTo(Object obj)方法,总是返回正整数
	public int compareTo(Object obj) {
		return 1;
	}
}

public class TreeSetTest2 {
	public static void main(String[] args) {
		TreeSet set = new TreeSet();
		Z z1 = new Z(6);
		set.add(z1);
		// 输出 true,表明添加成功
		System.out.println(set.add(z1)); // ①
		// 下面输出 set 集合,将看到有两个元素
		System.out.println(set);
		// 修改 set 集合的第一个元素的 age 变量
		((Z) (set.first())).age = 9;
		// 输出 set 集合的最后一个元素的 age 变量,将看到也变成了 9
		System.out.println(((Z) (set.last())).age);
	}
}
true
[practice.equals.Z@1, practice.equals.Z@1]
9

上面程序中两个Z对象通过equals()比较总会返回true,但通过 compareTo(Object obj)比较总是不会返回 0,因此两次向 TreeSet 中添加同一个元素,TreeSet会把它们当成不同的对象进行处理,最后 TreeSet 集合中会显示有两个对象,但实际上是同一个对象。

 

 

展开阅读全文
打赏
0
4 收藏
分享
加载中
更多评论
打赏
0 评论
4 收藏
0
分享
返回顶部
顶部