1.说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法
两个方法是一起的,equals方法对比两个对象是否值相等,如果相等他们的hashcode也要相等,如果如果你有需要要重写equals方法,也要重写hashCode方法(自己理解,(⊙﹏⊙))
object的默认实现为equals为:x == y,hashCode为对象的内存地址转换成的整数
public native int hashCode();//代表对象的特征
public boolean equals(Object obj) {//代表对象的比较
return (this == obj);
}
其中Object中若两个引用的equals()相等,那么两个对象的的hashCode()一定相同,
对于重写Object的类的equals()和hashCode()时,也需保证若两个引用的equals()相等,那么两个对象的的hashCode()一定相同,
这两个方法都是来自java.lang.Object类,在Object中hashCode()返回的是对象的地址值映射的hash值,equals()方法是对两个对象的地址值进行的比较;如果equals()方法的返回值相同,说明两个对象的地址值也是相同的,所以hashCode()的返回值也是相同的。
---------------------------------------------------------------------------------
1)什么是hashCode()?
hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值,也就是哈希码,哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。 在Java中,哈希码代表对象的特征。
2 )Object 对象中 hashCode()方法:
是由c++实现,根据对象的地址算出来的int类型的数值,hashcode()方法提供了对象的hashCode值,是一个native方法,返回的默认值与System.identityHashCode(obj)一致。
Object 对象中 equals()方法:
判断两个引用是否指向堆中的同一块内存,即同一个对象
3)所有的类都继承Object,因此对equals()和hashCode()都可以重写,
对于hashCode(),java中许多api都有实现,不同的类对hashCode()方法有不同的实现,因此不同的类根据不同的规则去做自己的hash码,可以根据地址或者字符串或者数字算出来的int类型的数值
不同的对象有不同的哈希码算法例如:
1、Object类的hashCode返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2、String类的hashCode根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。
3、Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如:
Integer i1=new Integer(100);
i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。
由此可以看出Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的 字段等)映射成一个数值,这个数值称作为散列值。
4)hashCode()方法有啥用处呢?
Set集合:元素无序,但不重复。
那么这里就有一个比较严重的问题了:如何判断两个对象相等呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
因为hashCode()可以返回该对象的特征,因此在HashSet集合(不允许有重复元素)中插入对象时,就可以利用待插入对象的hashCode值来判断是否可以插入(一般如果不重写hashCode()方法的话,hashcode的值就是对象的地址映射,因此就是地址值:hash值,进而判断该物理地址是否有元素了。。。)。。。。。。。。。。。。。。。。。。。
在向集合(如HashSet,TreeSet等)中添加元素的时候遵循的规则是:
A 判断对象的hashCode的值是否相同,如果不相同,认为这两个元素不相同,如果相同,转入B。
B判断两个对象的equals运算的值是否相同,如果不相同,认为两个对象是不相同的,
如果相同认为两个对象是相同的。
--------------------------------------------------------------------------------------------------------------
所以,Java对于eqauls方法和hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同;
2、如果两个对象的hashCode相同,它们并不一定相同 ;
如果一个类重写了equals()方法,则一定也要重写hashCode()方法,原因是:虽然equals()方法重写可以保证正确判断两个对象在逻辑是否相同,但是hashCode()方法映射的物理地址是不相同的,依然会将逻辑上相同的两个元素存入集合,但是第二个对象的内容会是Null.
2.这样的 a.hashcode() 有什么用,与 a.equals(b)有什么关系
两个对象的hashCode()值相等,两个对象不一定相等,
两个对象相等的规范是:两个对象的equals()相等,hashCode()也相等
3.有没有可能 2 个不相等的对象有相同的 hashcode
可能,hash冲突,使得不同的对象有相同的hash值
4.hashCode和equals的联系?
①两个obj,如果equals()相等,hashCode()一定相等
②两个obj,如果hashCode()相等,equals()不一定相等
原因:从散列的角度考虑,不同的对象计算哈希码的时候,可能引起冲突,大家一定还记得数据结构中冲突的解决方案吧
但是要这么设计,用两个函数,个人的理解是为了比较两个对象时更高效。
可以考虑在Java集合中,判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,如果两个hashCode()不相等,则两个对象不相等;
第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。
为什么这样做?个人的理解是让适当的函数完成适当的功能,毕竟hashCode()比equals()在某种程度上来得快。
5. 如何在父类中为子类自动完成所有的 hashcode 和 equals 实现?这么做有何优劣。
在覆盖equals方法的时候,你必须要遵守它的通用约定。下面是约定的内容,来自Object的规范[JavaSE6]
自反性。对于任何非null的引用值x,x.equals(x)必须返回true。
对称性。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true
传递性。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。
一致性。对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用该x.equals(y)就会一直地返回true,或者一致地返回false。
对于任何非null的引用值x,x.equals(null)必须返回false。
结合以上要求,得出了以下实现高质量equals方法的诀窍:
1.使用==符号检查“参数是否为这个对象的引用”。如果是,则返回true。这只不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。
2.使用instanceof操作符检查“参数是否为正确的类型”。如果不是,则返回false。一般来说,所谓“正确的类型”是指equals方法所在的那个类。
3.把参数转换成正确的类型。因为转换之前进行过instanceof测试,所以确保会成功。
4.对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域相匹配。如果这些测试全部成功,则返回true;否则返回false。
5.当编写完成了equals方法之后,检查“对称性”、“传递性”、“一致性”。
注意:
覆盖equals时总要覆盖hashCode 《Effective Java》作者说的
不要企图让equals方法过于只能。
不要将equals声明中的Object对象替换为其他的类型(因为这样我们并没有覆盖Object中的equals方法哦)
覆盖equals时总要覆盖hashCode
一个很常见的错误根源在于没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable。
在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生相同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。