在介绍java的集合时,我们提到,set是一个“罐子”。我们可以向其中放入各式各样的元素,这些元素没有顺序,但不能相同。其中,HashSet是最常用的一个实现类。
首先,我们看下HashSet的源码。
/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */ public HashSet() { map = new HashMap<>(); }
/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * the specified initial capacity and default load factor (0.75). * * @param initialCapacity the initial capacity of the hash table * @throws IllegalArgumentException if the initial capacity is less * than zero */ public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); }
可以看出,HashSet是基于HashMap实现的,用其来保存元素。保存时,由HashMap的key、value来实现。
回顾下集合的父接口Collection中提供的方法。
// Comparison and hashing boolean equals(Object o); int hashCode();
HashMap集合判断两个元素相等的标准:两个对象的equals方法相等,并且hashCode方法返回值也相等。
下面通过几个例子看一下:
1、只重写equals方法
public class HashSetTest1 { //重写equals方法,返回true public boolean equals(Object obj){ return true; } }
2、只重写hashCode方法
public class HashSetTest2 { //重写hashCode方法,返回1 public int hashCode(){ return 1; } }
3、重写hashCode、equals方法
public class HashSetTest3 { //重写hashCode方法,返回2 public int hashCode(){ return 2; } //重写equals方法,返回true public boolean equals(Object obj){ return true; } }
public static void main(String[] args) { HashSet test1 = new HashSet(); // 添加HashSetTest1 test1.add(new HashSetTest1()); test1.add(new HashSetTest1()); System.out.println("test1中元素的个数:" + test1.size()); HashSet test2 = new HashSet(); // 添加HashSetTest2 test2.add(new HashSetTest2()); test2.add(new HashSetTest2()); System.out.println("test2中元素的个数:" + test2.size()); HashSet test3 = new HashSet(); // 添加HashSetTest3 test3.add(new HashSetTest3()); test3.add(new HashSetTest3()); System.out.println("test3中元素的个数:" + test3.size()); }
执行结果为:
思考:
1、 HashSet中只把两个HashSetTest3对象当成了一个对象,因为只有他俩符合上述的规则,即equals、hashCode方法都相等。
2、如果需要重写equals方法,那么也应该重写hashCode方法。如HashSetTest1。
通过hashCode的返回值,我们可以看到,他返回的是一个int类型的值。在运算中,我们根据该元素的hashCode值计算出该元素的存储位置,以便快速定位。