Set集合解析何能进何不能进

Set集合何能加到集合中,何不能加进去?我们先来看看有什么问题;

有图有真相:

1.

		set.add(new People("zhangsan"));
		set.add(new People("lisi"));
		set.add(new People("zhangsan"));


运行结果:


这个结果的3个地址我们认为:三个People的对象,所以能进三个。

2.

		People p1 = new People("zhangsan");
		
		set.add(p1);
		set.add(p1);

运行结果:

这个结果我们会认为,两个P1的引用指向同一对象,所以只能进一个。

3.

		String s1 = new String("a");
		String s2 = new String("a");
		set.add(s1);
		set.add(s2);

运行结果:


这个结果会使我们解释有点晕,两个new出的String(两个对象),却只能进一次。


为了解决这个问题,我们要查看setadd()方法:

add

boolean add(E e)

如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向该 set 中添加指定的元素 e。如果此 set 已经包含该元素,则该调用不改变此 set 并返回 false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。


我们发现里面有equals方法,我们需要继续查看equals方法的源码,在Object类中:

public boolean equals(Object obj)

指示其他某个对象是否与此对象“相等”。 

equals 方法在非空对象引用上实现相等关系:

o 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。

o 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。

o 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。

o 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。

o 对于任何非空引用值 x,x.equals(null) 都应返回 false。

Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。


我们需要继续查看hashCode方法:

public int hashCode()

返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。 

hashCode 的常规协定是:

o 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

o 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

o 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)


在String方法中重写hashCode方法:

public int hashCode()

返回此字符串的哈希码。String 对象的哈希码根据以下公式计算: 

 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 

使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希值为 0。)

所以,我们会发现字符串类型,比较的不是地址信息了,比较的是字符串的值,如果两个字符串的内容一样,那么他们的hashCode的值也是一样的。


试验一下:

 

结果为:

hashCode的值一样;


总结: 当使用 HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值是否与增加的对象的 hash code 值一致;如果不一致,直接加进去;如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。


参考:

1.圣思园张龙老师的JavaSE视频教程。


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值