您的位置:首页 > 编程语言 > Java开发

Java中HashSet集合如何控制 元素唯一性 总结

2017-12-06 17:09 323 查看
近期在学习HashSet集合,HashSet集合的特点就是:该集合中的元素唯一,无序。而第一个特点 “唯一”
就是学习HashSet集合的重点!

例子:no.1新建一个HashSet集合对象 hs;

    no.2新建四个Student对象 st1(“张三”,18), st2(“李四”,19), st3(“王五”,20), st4(“张三”,18);

    no.3把四个学生对象放到集合中   hs.add(st1);   hs.add(st2);   hs.add(st3);   hs.add(st4);

    no.4用增强for来遍历输出集合中的元素
for(Student s:hs){
System.out.println(s.getAge()+"    "+s.getName());
}

结果:
张三  18


李四  19

王五  20

张三  18

为什么集合中存在相同元素呢??

/*注意:1.HashSet里面的add方法实际是调用的hashCode()方法和equals()方法来保证元素的唯一性;底层的逻辑是这样的:

先判断两个对象的hashCode是否相同:

如果不相同认为俩对象不相同,就往集合里面添加元素

如果相同,再用equals方法判断俩对象的所有的成员变量是否相同:

[b]俩对象的所有的成员变量都相同,则认为俩对象相同,不往集合里面添加元素[/b]

[b]俩对象的至少有一个成员变量不相同,则认为俩对象不相同,就往集合里面添加元素
[/b]

HashSet——>Set——>collection——>object   集合之间的继承关系是这样的,自然,HashSet调用的就是object类的hashCode()方法;而,object类的hashCode方法比较的是俩对象的地址值(默认情况下,Object中的hashCode()
返回对象的32位jvm内存地址。也就是说如果对象不重写该方法,则返回相应对象的32为JVM内存地址。),用new来新建对象根本不可能存在地址值相同的对象,也就是说任何俩对象的hashCode值都不相同;那么就立即往集合里面添加元素,所以就会有相同的元素出现


在上面的例子中
 *       由于Student类没有重写hashCode()方法和equals()方法,
 *    所以实际上调用的是object的hashCode()方法和equals()方法
 *    这个时候,每个对象的哈希值不一样的,在底层就根本不用equals()比较
 *    而是直接添加元素


但我们要注意,我们自己定义的类没有重写hashCode()和equals()方法;而当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()和hashCode()方法时,已经覆盖了object类的hashCode()和equals()方法。

1.     hashcode() 方法,在object类中定义如下:

 
public native int hashCode(); 说明是一个本地方法,它的实现是根据本地机器相关的。

当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double。。。。等等这些类都是覆盖了
hashcode()方法的。

例如在String类中定义的hashcode()方法如下: 

public int hashCode() {
int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count;
for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; }
return h; } 解释一下这个程序(String的API中写
到): s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,
^ 表示求幂。(空字符串的哈希码为 0。) 

2.
    equals()方法在object类中定义如下: public boolean equals(Object obj) { return (this == obj); } 很明显是对两个对象的地
址值进行的比较(即比较引用是否相同)。

比如在String类中如下: 

public boolean equals(Object anObject) { 

if (this == anObject) {

 
return true; 



if (anObject instanceof String) {

 String anotherString = (String)anObject; 

int n = count; 

if (n == anotherString.count) {

 char v1[] = value; 

char v2[] = anotherString.value; 

int i = offset; 

int j = anotherString.offset; 

while (n-- != 0) { 

if (v1[i++] != v2[j++])

 
return false; 



return true;




return false;



很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。

另外:

这里我们首先要明白一个问题:
 equals()相等的两个对象,hashcode()一定相等;

 equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。

换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码
在生成的时候产生冲突造成的)。

 反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,
也可能不等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hashset集合