Java中Set接口是Collectio的子接口,Set集合不允许包含相同的元素。如果添加相同的元素, add()会返回FALSE, 新元素不会加入。Set集合常用于元素为数字、字符串去重等,但是当元素为自定义对象类型时,Set去重是否与我们预计一致?下面将以HashSet为例,通过一系列试验来一步步验证。
结果:HashSet并没有认定两个“C罗”对象重复,三个实例都加入到了HashSet集合中。
仔细看putVal()方法,发现其对于新入的元素是否重复判断依据为以下两种
结果发现,自定义Object对象equals返回的值为false。接下来我们逐一看看它们的equals实现方式
(1) Integer对象的equals实现,通过阅读代码发现是判断依据是值是否相等。
(2) String对象的equals实现,其判断的依据为:先判断引用的对象是否是同一个,再逐个对比其字符串的值
(3) 而Object的判断依据为引用的对象是否是同一个,由于上面的两位足球运动员都是新new出来的,非同一个对象,所以equlas()返回结果为false
实验为结果两个Object对象的hash值并不相等,接下来我们看看它们对于hashcode()的具体实现
(1) 通过源码发现 Integer是通过对其value值来进运算行得到hash值。
(2) String也是通过对其value值来进计算行得到hash值,所以测试中结果为true
(3) 当查看Object的hashCode()方法时发现并无具体实现,通过查阅资料得知,JDK8的默认hashCode的计算是交给C++实现的,方法是通过和当前线程有关的一个随机数+三个确定值,运用Marsaglia's
xorshifschema随机数算法得到的一个随机数。所以两个不同的对象得到的hash值便不相同,测试结果也为false。(对于Object的hashCode()这里不做深入讨论,如果过深入了解的朋友也欢迎分享)
HashSet的底层是对HashMap的操作,其去重的原理通过hashCode()与equals()方法来判断是否重复。通过实验发现自定义对象没有成功去重的原因与JDK默认的Object对象hashCode()和equals()实现有关。对于自定义对象的去重,我们可以通过重写自定义对象的hashCode()与equals()使其按照我们所想要的规则进行去重操作。