HashSet底层是HashMap实现,不保证顺序恒久不变。优点是利用哈希表提高查询效率,缺点是元素不能重复。
一 哈希表如何提高查询效率
Object类中含有hashCode和equals方法,故String类重写了两种方法。其中重写的hashCode方法就相当于下图的hash函数,给对象映射到一个hash值,放到哈希表里,用于在哈希表存放位置的比较。重写的equals方法用于进一步判断对象是否相同,若地址相同,比如“bac和abc”按照String的hashCode方法有相同的地址,但是他们是不同的。故还需要通过equals方法判断对象内容是否相同。
String的hashCode源码:引用
“`
public int hashCode() {
int h = hash;
//如果hash值没有被计算过,并且字符串不为空,则进行hashCode计算
if (h == 0 && value.length > 0) {
char val[] = value;
//每个字符的hash值累加和为最终结果
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
“`
二 哈希表如何判断元素是否相同:
1> 哈希值是否相同 :判断的其实是对象的hashCode()方法是否相同(看对象是否在哈希表的同一个位置)
2>内容是否相同:用equals方法判断对象是否相同。
规则:若hash值不同,不必判断对象内容,返回false;若hash值相同,有必要判断对象内容,若在相同,返回true,否则false。
三 往hashSet中存放自定义对象
往hashSet中存放Car这个对象,其有名字和车轮数两个属性。由于hashSet不允许有重复的元素,下面的代码说明为啥添加两次“BWM,4”仍会输出结果。
public class Car{
String name;
int viechle;
public Car(String name,int viechle){
this.name=name;
this.viechle=viechle;
}
public String getNameViechle() {
return name+" "+viechle;//
}
public void setNameViechle(String name,int viechle) {
this.name = name;
this.viechle=viechle;
}
}
public class HashSetDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set <Car>hs=new HashSet<Car>();
hs.add(new Car("BWM",4));
hs.add(new Car("BWM",4));
Iterator<Car> it=hs.iterator();
while(it.hasNext()){
Car car=it.next();
System.out.println(car.getNameViechle());
}
}
}
输出:BWM 4 BWM 4
由于HashSet不允许元素重复,故需要判断元素是否相同,我们都知道ArrayList中判断元素是否相同用equals方法;但hashSet底层由哈希表实现,数据结构决定性质,故需要用hash表判断元素是否相同的方法,即需要hashCode和equals两个方法,对于hashSet,先通过hashCode判断元素在哈希表中的位置是否相同,在通过equals方法判断元素内容是否相同。(默认说明先调用hashCode方法,而且两个方法必须一起重写)故需要在上述代码Car类中添加重写的两个方法。
public class Car{
String name;
int viechle;
public Car(String name,int viechle){
this.name=name;
this.viechle=viechle;
}
public String getNameViechle() {
return name+" "+viechle;
}
public void setNameViechle(String name,int viechle) {
this.name = name;
this.viechle=viechle;
}
@Override
public int hashCode() {
return 31*name.hashCode()+viechle;
}
@Override
public boolean equals(Object obj) {
if(this==obj)return true;
if(!(obj instanceof Car)) throw new ClassCastException("类型转换异常");
Car car=(Car)obj;
return this.name.equals(car.name)&&this.viechle==car.viechle;
}
}
public class HashSetDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set <Car>hs=new HashSet<Car>();
hs.add(new Car("BWM",4));
hs.add(new Car("BWM",4));
Iterator<Car> it=hs.iterator();
while(it.hasNext()){
Car car=it.next();
System.out.println(car.getNameViechle());
}
}
}
输出:BWM,4