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中。

