对HashSet而言 系统采用hash算法决定集合的快速存取,集合元素,对HashMap而言,系统采用hash算法,跟据hash值来获取的key的存取位置,实现快速存取;
HashMap类的put源码:
public V put(K key,V value){
if(key==null)
return putForNullKey(value);
//根据key的keyCode计算hash
int hash=hash(key.hashCode());
//搜索指定的hash值在对应table中的索引
int i=indexFor(hash,table.length);
//获取table中的entry对象
for(Entry<K,V> e=table[i];e!=null;e=e.next){
Object k;
//判断key的hash值是否相等同时key equal是否相同
if(e.hash==hash && ((k=e.key)==key||key.equals(k)){
V oldValue=e.value;
e.value=value;
e.recordAccess(this);
return oldValue; //把老的值替换成新的值
}
}
//如果i处索引为空
modCount++;
//创建新的entry对象
addEntry(hash,key,value,i);
return null;
}
向hashMap添加key-value的时候,由其key的hashcode返回值,决定该key-value (entry对象)的存储位置;
当两个entry对象的key的hashCode返回值相同时候,将有key的euqals的比较值来比较是否为true,如果为true则覆盖,否则会产生新的entry对象;
//添加新entry对象
void addEntry(int hash,K key, V value,int buckIndex){
Entry<K,V> e=table[buckIndex];
table[buckIndex] =new Entry<K,V>(hash,key,value,buckIndex);
if(size++>=threshold) //如果ket-value对的数量超出了极限
resize(2*table.length); //进行扩容操作
}
这个代码设计很吊,如果table[buckIndex]处有entry对象,则新创建的对象则指向本来就有的对象,所以就形成了一个entry链,所以新创建总是entry在链的末尾;//指定初始化容量,负载因子创建hashMap
public HashMap(int intialCapacity,float loadFactory){
if(intialCapacity<0)
throw new 异常;
if(intialCapacity>MAXMUM_CAPACTITY)
intialCapacity=MAXMUM_CAPACTITY;
if(loadFactory<0||Float.isNaN(loadFactory))
throw new 异常;
int capacity=1;
while(capacity<intialCapacity) //capacity小于初始化的值,则capacity扩大为2 的n次方
capacity<<1;
threshold=(int)(intialCapacity*loadFactory); //最大极限值则是初始化值*负载因子
table=new Entry[capacity]; //创建一个新的Entry对象数组
int(); //进行初始化操作;
}
初始化的时候,会产生一个table数组,这个数组里面放的元素,我们称作为“桶” bucket,每个bucket会有相对应的索引,我们可以根据索引来进行取值;
public V get(Object key){
if(key==null)
return getForNullKey();
int hash=hash(key.hashCode);
for(Entry[K,V] e=table[indexFor(hash,table.length)];e!=null;e=e.next)
{
Object k;
if(e.hash==hash&&((k==e.key)==key.equals(k))
return e.value;
}
return null;
}
如果hashmap只有一个entry对象,则hashmap通过索引直接取出该桶内的entry,如果是一条entry链,则就会遍历全部,如果该要找到的对象在该链的底部的最后一个entry,
所以要重写equals和hashCode来进行判断是否相同。如果一条entry链全部遍历则会降低hashMap的性能;
hashMap的默认是16
总的来说:
HashMap底层是key-value对当成整体进行处理,这个整体就是entry对象;底层则是一个Entry[]来保存所有的key-vaue对,当需要存储一个entry对象,会根据hash算法,来存到相应的位置,如果要取一个entry对象,也会根据hash算法来找到相应的位置进行获取;
hashMap一开始的时候初始化,不要空间大小不要初始化的太高;
负载因子默认是0.75,增大负载因子,会提高hashMap内部查询例如put,get。;降低负载因子,会提高hashMap的查询,反而增大了hashMap的空间开销
总的来说set底层就是hashMap,为了要符合hashMap的key-value对所以hashSet底层定义了一个静态的object类可以充当value;
set集合只是用了map的key而没有用value;