HashSet在java中的工作原理
在本教程中,我们将了解java中的Hashset
Java HashSet:
这是corejava访谈中的一个常见问题,因此在本教程中,我们将看到HashSet是如何工作的java.
我们已经了解了hashMap在java中的工作方式,以及hashMap和HashSet之间的区别。
首先让我们看看Hashset的介绍,然后我们将了解它的内部结构。
HashSet 哈希集:
HashSet实现不允许重复的Set接口value.It 不是同步的,也不是线程安全的。
重复的定义可能相当棘手sometimes.Lets 考虑两个案例。
-对于基元类型(如integer、String)
-对于自定义对象。
对于基元类型:
对于primitives类型,它非常直接。让我们举个例子看看:
让我们创建一个java程序:
package org.arpit.theitroad; import java.util.HashSet; public class HashSetMain { public static void main(String[] args) { HashSet nameSet=new HashSet(); nameSet.add("Arpit"); nameSet.add("Arpit"); nameSet.add("john"); System.out.println("size of nameSet="+nameSet.size()); System.out.println(nameSet); } }
运行上述程序时,将得到以下输出:
size of nameSet=2 [Arpit, john]
所以我们尝试了两次添加字符串“Arpit”,但由于HashSet不允许重复值,它将在HashSet中添加一次“Arpit”
对于自定义对象:为了理解HashSet在自定义对象中的工作方式,您需要理解java中的hashcode和equals方法。
让我们创建一个名为Country的类,并在其中实现equals方法。
package org.arpit.theitroad; public class Country { String name; long population; public String getName() { return name; } public void setName(String name){ this.name = name; } public long getPopulation() { return population; } public void setPopulation(long population) { this.population = population; } public String toString() { return name; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Country other = (Country) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
创建 main 类:
package org.arpit.theitroad; import java.util.HashSet; public class HashSetCountryMain { public static void main(String[] args) { HashSet countrySet=new HashSet(); Country india1=new Country(); india1.setName("India"); Country india2=new Country(); india2.setName("India"); countrySet.add(india1); countrySet.add(india2); System.out.println("size of nameSet="+countrySet.size()); System.out.println(countrySet); } }
运行上述程序时,将得到以下输出:
size of nameSet=2 [India, India]
现在您一定想知道,即使两个对象相等,为什么HashSet包含两个值而不是一个。这个是因为第一个HashSet为那个key对象计算hashcode,如果hashcode相同,那么它只检查equals方法,并且因为上面两个country对象的hashcode使用默认的hashcode方法,两者都有不同的内存地址,因此哈希代码也不同。现在让我们在上面的Country类中添加hashcode方法
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; }
Run above main program again, you will get following output:
size of nameSet=1 [India]
现在我们已经很好地理解了HashSet,让我们看看它的内部表示:
哈希集的内部工作:
当您向HashSet添加任何重复元素时,add()方法返回false,并且不向HashSet添加重复元素。
如何添加方法返回false?为此,我们需要在JavaAPI中查看HashSet的add方法
public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable { private transient HashMap<E,Object> map; // PRESENT is dummy value which will be used as value in map private static final Object PRESENT = new Object(); /** * Constructs a empty map.so hash * */ public HashSet() { map = new HashMap<E,Object>(); } // return false if e is already present in HashSet public boolean add(E e) { return map.put(e, PRESENT)==null; } // other HashSet methods }
因此,从上面的代码可以清楚地看出,HashSet使用hashMap检查重复的元素。
我们知道,在HashMap中,键应该是唯一的。所以HashSet使用这个概念,当元素被添加到HashSet中时,它作为Key.This HashMap需要一些值,因此在这个HashMap中使用一个伪对象(PRESENT)作为值。PRESENT是用于内部映射的虚拟值。请参见添加方法:
// return false if e is already present in HashSet public boolean add(E e) { return map.put(e, PRESENT)==null; }
所以这里会有两个情况
- map.put(e,PRESENT)将返回null,如果元素不在该映射中。所以呢地图输入(e,PRESENT)==null将返回true,因此add方法将返回true,元素将添加到HashSet中。
- map.put(e,PRESENT)将返回旧值,如果元素已经存在于该映射中。所以呢地图输入(e,PRESENT)==null将返回false,因此add方法将返回false,元素将不会添加到HashSet中。