我们知道在使用HashSet集合时,也就是在用HashMap集合,这是因为HashSet的底层是HashMap,
public HashSet() {
map = new HashMap<>();
}
在详述HashSet中的add()方法之前,我们要知道HashMap中的hash,因为在add()的底层代码中hash很重要(因为要通过hash来判断key的值是否相同,进而决定是否add()是否可以添加成功):
static final int hash(Object key) {//此处的key就是HashMap中的key,也就是HashSet中的add()方法里的参数对象
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//此处为三目运算,通过hashCode来决定h的值,
//其中使用hashCode的返回值是由add()方法里的参数对象的类型决定的
}
hashCode的返回值 主要分为三种:
- 基本数据包装类:如果值相同,则返回值也相同,且返回值就是输入的值
- String类:如果内容相同,则返回值也相同
- 自定义类类型:如果地址相同,则返回值相同,否则不同
public class Test {
static int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
//基本数据包装类
Integer x = 20;
Integer y = new Integer(20);
System.out.println(hash(x));
System.out.println(hash(y));
//String类
String str1="hashCode";
String str2=new String("hashCode");
System.out.println(hash(str1));
System.out.println(hash(str2));
//自定义类类型
Self s1 = new Self();
Self s2 = new Self();
System.out.println(hash(s1));
System.out.println(hash(s2));
}
}
class Self{}//自定义一个类
上面输出的结果就是:
20
20
147694806
147694806
5433712
2430314
之所以会这样,是因为:Integer 、String 中都重写了父类(Object)中的hashCode()方法,而自定义类Self未重写(所以调用的是父类中的hashCode()方法):
- Integer中重写的hashCode()方法:
@Override
public int hashCode() {
return Integer.hashCode(value);//传入一个Integer值
}
public static int hashCode(int value) {
return value;//返回该值
}
- String中重写的hashCode()方法:
public int hashCode() {
int h = hash;//hash默认值为0
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
总之,上面这串代码,最初的h值相同,add()中的参数相同,所以最后的返回值h相同。
而父类中的hashCode是由参数地址决定的,地址相同,返回值相同,地址不同,返回值也不同
好了,明白了hash和hashCode,我们就详细说明HashSet中的add()方法( 一 )(详尽版)吧