1,对HashSet新建对象的分析
HashSet<String> set=new HashSet<String>();
创建一个HashSet类的对象,new HashSet<String>()调用了HashSet中的无参构造方法
public HashSet(){
map=new HashMap<>();
}
实质又调用了HashMap中的无参构造方法
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
2,hash方法
因为在对add方法进行分析时,会用到hash方法,先分析hash方法
01,传入String类型的值:比较内容是否相同,相同的内容返回值是相同的
public class Test(){
static int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} // hash方法:返回值为int类型的,其中又调用了hashCode方法
public static void main(String[] args) {
int hash=hash("tom"); //hash方法中传入String类型的值后,key不为空,执行三目运算中冒号后边部分,调用hashCode方法
System.out.println(hash);
hash=hash(new String("tom"));
System.out.println(hash);
}
输出为:
115027
115027
其中String类中的hashCode方法如下,经过运算返回int类型的值
public int hashCode() {
int h = hash;
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;
}
02,传入int类型的值,比较数值,数值相同返回值相同。
public class Test(){
static int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} // hash方法:返回值为int类型的,其中又调用了hashCode方法
public static void main(String[] args) {
hash=hash(15);
System.out.println(hash);
hash=hash(15);
System.out.println(hash);
}
输出为:
15
15
其中Integer 类中的hashCode方法如下,经过运算返回int类型的值,传入返回的值。
public static int hashCode(int value) {
return value;
}
03,对传入的自定义类的对象:比较地址,返回int类型的值
public class Test(){
static int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} // hash方法:返回值为int类型的,其中又调用了hashCode方法
public static void main(String[] args) {
hash=hash(new Student());
System.out.println(hash);
hash=hash(new Student()); //两个地址:运算结果不同
System.out.println(hash);
}
}
//自定义类:
class Student{
}
输出为:
5433712
2430314
自定义类中的HashCode说明
因为自定义类中没有重写父类的hashCode方法,所以该类中的hashCode方法默认继承自父类Object,经过运算返回int类型的值。
//Object类中定义的hashCode方法:
public native int hashCode();
3,HashSet中add方法是怎样执行的
HashSet<String> set=new HashSet<String>();
set.add("tom");
set.add("tom");
set.add("lucy");
代码分析:每次执行代码set.add();时调用add方法,传入的e的值为tom,再调用HashMap中的put方法,传入的key的值为tom,(HashSet存储的数据实质存在了HashMap的key),再调用putVal方法(其中的hash(key)返回int类型的数值)
//HashSet中的add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//HashMap中的put方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//HashMap中的putVal方法
//详述putval方法
//第一次存储tom时
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { //Node<K,V>[] tab;定义了一个集合,Node<K,V> p;定义集合中的值,table是全局变量,未初始化之前默认值为null.
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) //该if语句执行,将值赋给tab后,前半部分返回值为true,因为逻辑或遇真短路(后半部分不再运算),所以if条件满足,执行下一行代码。
n = (tab = resize()).length; //resize()方法将集合重置,重置后有了长度,且重置后的长度为16,因为调用了HashMpa中定义的常量【static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16】,然后执行下一行代码。
if ((p = tab[i = (n - 1) & hash]) == null) //i = (n - 1) & hash语句得到一个位置下标,对于p = tab[i = (n - 1) & hash],第一次存储集合为空,所以if条件成立,执行下一行代码添加tom,然后跳出该if语句。
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount; //跳出if语句后执行该语句,实现将tom存储。
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
//关于resize()方法
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table; //table是null,返回值为newTab,是一个重置的有长度的集合。
.......
if (oldTab != null) {
}
return newTab;
}
//第二次存储tom时.
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) //table不为空,n = tab.length也不等于0,执行下一个if语句.
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null) //因为同一个String类型的值,hash相同,n为固定的长度,所以获取的下标与第一次相同,此时位置不为空,所以不添加到tab[i],执行else语句
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) //两次都是tom,所以hash相同,p.hash == hash返回true,((k = p.key) == key || (key != null && key.equals(k)))返回true,执行e=p;语句,执行下一个if语句
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { //此时e不为空,所以一定会执行return oldValue;
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue; //关掉方法,不存储数据。
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
//第三次时:存储lucy。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) //table不为空,n = tab.length也不等于0,执行下一个if语句.
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null) //lucy调用hash方法后得到得值与tom不同,所以经过运算之后得到一个i,且此时该下标处为空,将lucy添加进去,跳出这个if语句。
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount; //跳出if语句后执行该语句,实现将lucy存储。
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
//常量池机制:在常量池中存储值时,先判断常量池中是否存在该值,如果存在将不再进行添加,不存在时才添加。