提升下自己的表达及总结能力,也许若干年后可以去做一名合格的讲师~~~
一、覆写equals方法
为什么要覆写equals方法呢?覆写的原则是什么呢?原因以下:
有时候做到 两个实例对象在 逻辑上是否相等 时 就要覆写 equals 方法了。比如两个Person年龄、姓名、性别都相等时可以认为是一个人(但显示生活是:身份证ID相同的才是同一个人),这时就要覆写equals方法了:
@override
public booleanequals(Object obj){
if(obj==null){return false ;} //---line 2
if(!obj instanceof Person){return false ;} //---line 3
Person this_person = (Person) obj ; //--line 4
if(this.age = this_person.age&&this.name = this_person.name&&this.sex=this_persion.sex){return ture ;}
return false ;
}
一定不要漏洞第三行 instanceof 判断,否则如果参数obj不是Person类型会抛出 类型匹配异常ClassCaseException.
好了,虾米是如何覆写equals方法,需要遵守的约定是什么?
1、一致性
line 2 如果参数对象是null空值要返回false.line 3 参数对象不是待比较对象的类型or待比较对象的子类型要返回false.
2、自反性
x.equals(y)==true 则 y.equals(x)也要返回ture.这点就不在此赘述了。
3、传递性
x.equals(y)==true , y.equals(z)==true ,则 x.equals(z)也要返回true.
默认的equals方法比较的是引用的内存地址是否相等。JDK源码如下:
public boolean equals(Object obj) {
return (this == obj);
}int 、float 等基本类型比较的是值,因为内部重写了equals方法。 String 首先比较的是引用的是否是同一块内存地址,是则返回true;不是比较内容是否相等。所以比较的也是值。付String类equals源码: public boolean equals(Object anObject) {
1014 if (this == anObject) {
1015 return true;
1016 }
1017 if (anObject instanceof String) {
1018 String anotherString = (String)anObject;
1019 int n = count;
1020 if (n == anotherString.count) {
1021 char v1[] = value;
1022 char v2[] = anotherString.value;
1023 int i = offset;
1024 int j = anotherString.offset;
1025 while (n-- != 0) {
1026 if (v1[i++] != v2[j++])
1027 return false;
1028 }
1029 return true;
1030 }
1031 }
1032 return false;
1033 } 其他对象比较的是引用地址。
二、覆写hasCode方法
为什么要覆写hasCode方法,覆写原则又是什么呢?
当我们覆写了equals方法后,使用非has的集合时如List,没关系可以正常存取,因为List不关注待add的对象是否已经存在。但是在使用Set、Map等只能保存唯一的实例对象时,add对象时怎么判断该对象是否已存在呢?没错,就是通过hasCode进行判断的(插一曲:JDK源码为什么不用equals方法判断呢?我也不知道,也许是因为hasCode本身就是快速存取散列数据的原因吧)。
所以我们在重写hasCode时要遵循第一条约定:相同的对象,hasCode值要相等;不相同的对象的hasCode值尽量分不到不同的has桶中;hasCode不相等的两个对象,对象的equalse返回true.代码就是:
x.equals(y)==true 则 x.hasCode == y.hasCode ;
x.hasCode != y.hasCode ,则 x.equals(y) == false ;
如果只覆写equals而不覆写hasCode ,就会导致两个逻辑相等的对象的hasCode值不相等。这样Set\Map就会认为这是两个不同的对象,造成混乱。
如果两个对象不相等,那么hasCode值尽量也不要相等。设计者设计hasCode的初衷就是为了更快的存取散列数据,所以 Set Map等has集合比较和取对象都是根据hasCode的值。所以hasCode不等的对象会被分配到不同的has桶中。
那么如何来重写hasCode方法呢,原则又是什么呢?
针对对象中的每个域做如下转换:
1.byte、char、short、int 做 (int)val转换
2、float 做 Float.toBigInts(f)
3、long 、double、待补充
最后综合各域:
result = 31*result + c ;
做31*result的目的是让 字母相同但是排列顺序不同的字符串的has值不同。31是素数还是基数,如果是偶数,乘以2就是左移数据,容易造成溢出。个人理解是:31==2~5 - 1 最小的素基数。