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集合的重点!
例子: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集合是如何保证元素的唯一性的?
- 关于HashSet集合是如何保证元素唯一性的
- 分析HashSet,HashMap源码,如何保证HashSet集合元素唯一性。
- HashSet集合是如何保证元素的唯一性的?
- Java中如何循环删除一个集合(如List)中的多个元素
- 循环的时候如何安全地删除java集合的元素
- 如何在页面中使用Acegi权限集合和taglib控制页面元素
- java中集合类HashSet、ArrayList、LinkedList总结
- Java集合HashSet-ArrayList-HashMap的线程同步控制方法和区别
- Java如何克隆集合——深度拷贝ArrayList和HashSet
- 解说HashSet如何保证元素的唯一性
- Java学习疑点(6)--Set集合添加元素时底层如何实现无重复元素?
- java中TreeSet集合如何实现元素的判重
- Java集合HashSet-ArrayList-HashMap的线程同步控制方法和区别
- Java中如何删除一个集合中的多个元素
- 如何删除Java集合中的元素
- Java中如何循环删除一个集合(如List)中的多个元素
- Java如何随机取出集合中的元素
- Java中如何循环删除一个集合(如List)中的多个元素
- Java集合HashSet-ArrayList-HashMap的线程同步控制方法和区别