这次我们了解一下关于HashSet集合如何做到重复的。(这次的文章改编于网上某篇文章,但是又加入了我对于HashSet集合的一些理解,望谅解!)
Java中关于HashSet添加自定义对象时,自定义类要重写equals方法和hashCode方法的前世今生...
先了解一下HashSet集合的基本情况:
据我所知HashSet集合是没有顺序,也不允许重复[对象的重复]。
对象的重复:指的就是在内存中,所在的内存编号一样的同一个对象。
内存编号指的就是哈希码(哈希码一般是类名和对象所在内存地址的十六进制数字表示 的组合)。
然后了解一下相关的知识:
现实生活中只要属性相同,我们就认为那是同一个对象。
计算机中比较同一个对象的方法不同[计算机使用内存地址,即哈希码]。
于是,就需要重写equals方法和hashCode方法来让程序的运行结果符合现实生活,不同的类对于equals方法和hashCode方法的要求不一样。
附:基本数据类型的实现类都已经重写了上面的两个方法。
技术实现原理:
当你利用HashSet创建一个对象时,在HashSet的构造方法中,先用hashCode方法计算出该对象的哈希码。
比较顺序以及原理
(1).如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中!
(2).如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象(判断的标准是:属性是否相同)
1>.相同对象,不添加!
2>.不同对象,添加!
这时有两个疑问:
1.为什么哈希码相同了还有可能是不同对象?
按照Object类的hashCode方法,是不可能返回两个相同的哈希码的。(哈希码唯一标志了对象)
Object类的hashCode方法返回的哈希码具有唯一性(地址唯一性),但是这样不能明确的确定两者是不是同一个对象。(这个逻辑就是:属性相同的对象被看作同一个对象。)
所以综上所述两个对象重复的标准:哈希码相同且属性相同。
2.为什么经过比较哈希码还需要借助equals方法判断?
为了让程序的运行逻辑符合现实生活,区分哈希码相同但不是同一个对象的对象。(自定义的类要你自己重写。)
重写的原因是什么?
在现实中,不同的类对于equals方法和hashCode方法的要求不一样。
一个自定义的类:
package LQJ.newer.a3; public class person { private String name; public person(String name) { this.name = name; } //重写的hashCode方法 @Override public int hashCode() { return name.hashCode(); } //重写的equals方法 @Override public boolean equals(Object obj) { if (this == obj){ return true; } if (obj instanceof person){ person p = (person) obj; return this.name.endsWith(p.name); } return false; } //重写的toString方法 @Override public String toString() { return name; } }
主类调用:
package LQJ.newer.a3; import java.util.HashSet; import java.util.Iterator; public class HashSetMAIN { public static void main(String[] args) { HashSet<person> set = new HashSet<person>(); set.add(new person("张三")); set.add(new person("王二")); set.add(new person("刘四")); set.add(new person("李武")); set.add(new person("剑皇")); set.add(new person("王二")); // 迭代器对象:用来对数据结构取数据的一个对象 // 得到set的迭代器 Iterator<person> iter = set.iterator(); // 判断迭代器中能不能迭代出数据 while (iter.hasNext()) { // 取出数据 person s = iter.next(); System.out.println(s.toString()); } } }