Map:健值对,健不能重,和set一样,有HashMap、LinkedHashMap、TreeMap三种。
HashMap,基于散列表实现,查找速度快(依赖hashcode()和equals()),存放元素无序。
ConcurrentHashMap,线程安全的HashMap,用于替代HashTable(线程安全,但基于整个对象的锁实现的,效率不高),而ConcurrentHashMap是采用分段加锁的方式实现,提升了效率。
LinkedHashMap,基于散列表、双向链表实现。如HashMap的查找速度,遍历时有序(默认为插入顺序,可通过构造方法设置“最近最少使用(Least Recently Used)顺序”)。
TreeMap,基于红黑树实现,存放有序(依赖Compareable)。
1) HashMap实现原理,如何解决冲突
HashMap使用Hash表,即数组+链表的方式存储数据。
存储时,通过key.hash获取一个hash的数值,再模上hash表的长度,得到key值在hash表中的索引位置。如果此位置为空则直接添加值;如果此位置有值,则将新的key放到此位置上,同时新值对应的Entry的next指向之前的值,即在链表的头部插入数据。
优化:当数据量越来越多,链表就会越来越长,性能也就越差。HashMap里面设置了一个因子,随着Entry的sise越来越大,Entry[]会以一定的规则加长长度。
2) HashTable实现原理
它的每个方法都是synchronized类型,对hashtable的任何操作都会把整个表锁住,因此是线程安全的。当put数据时,会先计算hash值,如果此位置没有元素则直接添加,如d1,如果已有元素,会按照链表的方式将元素插入在链表的头部,如aa。
3) ConcurrentHashMap实现原理
内部使用Segment数组,每个Segment类似于HashTable,操作时是锁住某个Segment对象,其他线程可以并发操作其他Segment对象,因此效率要比HashTable高.
4) hashcode()和equals()
hashcode()和equals()即用于识别对象的身份。
在HashMap或类似的实现中,查找一个对象,是通过hashcode()返回的散列值映射到一个范围内的下标,在通过equals()比较此下标连接的链表是否存在相同的对象。
简单来说,hashcode()用于参考、快速定位(缩减范围),真正是否等于是依赖equals()。
覆盖这两个方法有什么原则呢?
equals()的覆盖,主要是基于此对象的业务。
而hashcode()的覆盖原则,详情可参见《Effective Java》的“覆盖equals时总要覆盖hashcode”一节。
有几个比较重要的原则:
1、两个equals相等的对象,其hashcode是相等的。
2、两个equals不等的对象,其hashcode有可能是相等的。
3、好的hashcode()应产生分布均匀的散列码。
和set一样,map的key值是不能重复的,如果是自定义对象,是通过hashcode和equals来判断是否为同一个对象的,因此如果以对象作为key值,需要注意这两个方法的重载。
5) LinkedHashMap的两种遍历方式
public static void useLinkedHashMap(){
System.out.println("--LinkedHashMap根据输入的顺序输出--");
LinkedHashMap<String, String> linkedHashMap=new LinkedHashMap<>();
linkedHashMap.put("3", "Value3");
linkedHashMap.put("1", "Value1");
linkedHashMap.put("2", "Value2");
linkedHashMap.put("b", "ValueB");
linkedHashMap.put("a", "ValueA");
linkedHashMap.get("2"