== 简单而又实在
- 在基本数据类型中比较的是两个数据的值。
- 在对象中比较的是两个对象的地址。
equal 追求的是“逻辑相等”
对大部分的对象来说,使用父类的 Object.equal()
就已经足够使用了。而 Object.equal()
实现的功能就是比较两个对象的地址是不是相同的。
- 例如我们比较两个 Thread 是不是同一个线程,只要比较他们的地址就可以达到我们的目的了。
但依旧有些类,要求的不是绝对的相同(指向同一个对象),而是需要的逻辑上的相同(感官上觉得这两个类值是相同)。
- 例如我们常用的 String ,Integer,Data 等,则需要根据他们的特性,去复写一个去判断值是不是相等的
equal()
方法。
复写 equal()
的需要满足:
- 自反性(reflexive)。对于任何非
null
的引用值x
,x.equals(x)
必须返回true
。 - 对称性(symmetric)。对于任何非
null
的引用值x
和y
,当且仅当y.equals(x)
返回true
时,x.equals(y)
必须返回true
。 - 传递性(transitive)。对于任何非
null
的引用值x
、y
和z
。如果x.equals(y)
返 回true
,并且y.equals(z)
也返回true
,那么x.equals(z)
也必须返回true
。 - 一致性(consistent)。对于任何非
null
的引用值x
和y
,只要equals
的比较操作 在对象中所用的信息没有被修改,多次调用x.equals(x)
就会一致地返回true
,或者一致的返回false
。 - 非空性 (Non-nullity)。对于任何非
null
的引用值x
,x.equals(null)
必须返回 false 。
- 什么情况会违法对称性呢?
比如说我们在自己的IgnoreCaseString
类中,复写equal()
方法,使这个方法在与String
比较时,忽略String
的大小写。但在"Abc".equal(ignoreCaseString1)
在反过来,结果就会出现不同。
public static class IgnoreCaseString {
private String string;
public IgnoreCaseString(String str){
this.string = str;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof String) {
return string.equalsIgnoreCase((String) obj);
}
return super.equals(obj);
}
@Override
public String toString() {
return string;
}
}
public static void main(String[] args) {
String str = "Abc";
IgnoreCaseString str1 = new IgnoreCaseString("Abc");
System.out.println(str1.equals(str));// true
System.out.println(str.equals(str1));// false
}
- 什么时候会违法传递性
A,B,C 三个类。A 和 B 同时复写了equal()
方法时,会出现这种可能。
复写
equal()
尽量不要去想兼容其他类型的比较。而时去判断是否和同一个类是否相同。通常建议这样去判断:
(1)用==
去判断是否为同个对象
(2)用instanceof
去判断是否属于同个类或同个接口类型,如 Set,List 这类
(3)检查关键数据是否相同,这点根据自身的需求来处理
equal 忘不了的 hashcode
对象相等(equal()
判断为相等)可以保证 hashcode 相等。但不能反着推,长点心吧,毕竟连 map 都有知道哈希碰撞,弄个链表红黑树又不是用来玩的。
复写 hashcode
方法时为了不相等的对象产生不相等的哈希值。
怎么样复写,🐦了。