HashMap结构
数组+链表+红黑树
为什么使用链表 ----》为了解决hash冲突
为社么使用红黑树-----》链表查询速度慢
构造器
【1】空参构造器
调用空参构造器,当向集合添加数据的时候
【2】调用有参构造器
put方法
hash表中的单向链表节点个数达到8,并且数组长度超过64,链表就会变为红黑树
当元素个数小于6,则还会变为链表结构,如果一直是删除操作,则到2个才会变为链表
HashMap的底层实现结构
数组+链表+红黑树
HashMap的添加原理
① 计算key的hash值
② 根据key的hash值和数组的长度计算索引位置
如果该位置没有值:直接添加
如果该位置有值:判断hash值是否一样
一样:判断地址是否一样
一样: 确定是相同数据,进行替换操作
不一样: 则会进行equals操作
一样: 确定是相同数据,进行替换操作
不一样: 则继续往下判断下一个节点,直到下一个是null为止!然后链接
不一样:则继续往下判断下一个节点,直到下一个是null为止!然后链接
HashMap判断两个key值是否一样是根据对象的,hashCode()+equals()
HashMap的容量机制
在实例化对象的时候,没有容量
在第一次添加数据的时候,容量设置为16,临界值设置为12
在后续添加数据过程中,一旦数据的个数超过了临界值,则进行扩容,扩容原则是原容量的2倍
HashMap中的方法
public class AAA {
@Test
public void a(){
HashMap<Object, Object> hm = new HashMap<>();
//1.添加 put(K k,V v) 如果k不在集合中,则返回null,将k和v添加到集合中
//如果k已经存在,则返回集合中v的旧值,将新的值替换集合中的旧值(注意:只是替换值value,key是不会替换的)
Object put = hm.put(123, "张三");
System.out.println(put); //null
hm.put(345,"李四");
hm.put(888,"王五");
Object put1 = hm.put(123, "丽丽");
System.out.println(put1); // 返回 张三
//2.putAll(Map<> m) 将一个map集合添加到集合中
HashMap<Object, Object> hm1 = new HashMap<>();
hm1.put(666,"菲菲");
hm.putAll(hm1);
System.out.println(hm1);
//3.remove(K k) 返回删除k对应的value ,如果k不存在,则返回null
Object remove = hm1.remove(123);
System.out.println(remove);
Object remove1 = hm1.remove(777);
System.out.println(remove1);
//4.remove(K k,V v) 删除键值对,如果不存在,则返回false
boolean b = hm1.remove(345, "里");
System.out.println(b);
boolean b1 = hm1.remove(345, "李四");
System.out.println(b1);
//replace(K k,V v,V1 v1)
boolean replace = hm1.replace(888, "王五", "王五男");
System.out.println(hm1);
//replace(K k,V v) 返回原来的对象
Object o = hm1.replace(666, "哟哟");
System.out.println(o);
//
Set<Map.Entry<Object, Object>> entries = hm1.entrySet();
for(Object o1:entries){
System.out.println(o1);
}
//get(K v) 返回k值对象的value,如果k不存在就返回null
Object o1 = hm1.get(777);
System.out.println(o1);
//getOrDefault(K k,DdfaultValue v) 根据k获取value,如果k不存在,则返回默认value
Object t = hm.getOrDefault(777, "张安");
System.out.println(t);
//clone() 复制一个新的集合
Object clone = hm1.clone();
System.out.println(clone);
System.out.println(clone==hm1);
//集合是否包含指定的key
boolean b2 = hm1.containsKey(333);
System.out.println(b2);
//集合是否包含指定的value
boolean b3 = hm1.containsValue("李四");
System.out.println(b3);
//clear()清空集合
hm1.clear();
System.out.println(hm1);
}
HashMap和HashTable区别
(1)线程安全性不同
HashMap是线程不安全的,HashTable是线程安全的,其中的方法是Synchronize的,在多线程并发的情况下,可以直接使用HashTable,但是使用HashMap时必须自己增加同步处理。
(2)是否提供contains方法
HashMap只有containsValue和containsKey方法;HashTable有contains、containsKey和containsValue三个方法,其中contains和containsValue方法功能相同。
(3)key和value是否允许null值
Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
(4)数组初始化和扩容机制
HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。