目录
HashMap、LinkedHashMap、TreeMap、Hashtable、Properties区别
Map接口
Map与Collection并列存在。用于保存具有映射关系的数据:key-value
Map 中的 key 和 value 都可以是任何引用类型的数据
Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
常用String类作为Map的“键”
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value
Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类
Map接口常用方法
添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
void putAll(Map m):将m中的所有key-value对存放到当前map中
Object remove(Object key):移除指定key的key-value对,并返回value
void clear():清空当前map中的所有数据
元素查询的操作:
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value(先调用HashCode(),equals())
int size():返回map中key-value对的个数
boolean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
元视图操作的方法:
Set keySet():返回所有key构成的Set集合
Collection values():返回所有value构成的Collection集合
Set entrySet():返回所有key-value对构成的Set集合
import org.junit.Test;
import java.util.*;
/**
* @author light
* @Description Map接口常用方法
* @create 2023-01-19 15:41
*/
public class MapTest {
@Test
public void test1(){
/*
* 添加、删除、修改操作:
* Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
* void putAll(Map m):将m中的所有key-value对存放到当前map中
* Object remove(Object key):移除指定key的key-value对,并返回value
* void clear():清空当前map中的所有数据
*/
//添加
Map map=new HashMap();
map.put("AA",123);
map.put("BB",345);
map.put("CC",789);
map.put("DD",234);
map.put("EE",567);
//修改
map.put("AA","abc");
System.out.println(map);
Map map1=new HashMap();
map1.put("ff","qwe");
map1.put("KK",5667);
map.putAll(map1);
System.out.println(map);
//remove(object key)
Object remove = map.remove("K");
System.out.println(remove);
System.out.println(map);
//clear()
map.clear();
System.out.println(map.size());
}
@Test
public void test2(){
/*
* 元素查询的操作:
* Object get(Object key):获取指定key对应的value
* boolean containsKey(Object key):是否包含指定的key
* boolean containsValue(Object value):是否包含指定的value
* int size():返回map中key-value对的个数
* boolean isEmpty():判断当前map是否为空
* boolean equals(Object obj):判断当前map和参数对象obj是否相等
*/
Map map=new HashMap();
map.put("AA",123);
map.put("BB",345);
map.put("CC",789);
map.put("DD",234);
map.put("EE",567);
System.out.println(map.get("AA"));
}
@Test
public void test3(){
/*
* 元视图操作的方法:(遍历)
* Set keySet():返回所有key构成的Set集合
* Collection values():返回所有value构成的Collection集合
* Set entrySet():返回所有key-value对构成的Set集合
*
*/
Map map=new HashMap();
map.put("AA",123);
map.put("BB",345);
map.put("CC",789);
map.put("DD",234);
map.put("EE",567);
//遍历所有key集:keySet()
Set set=map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("************************");
//遍历所有value集
Collection coll=map.values();
// Iterator iterator1 = coll.iterator();
//
// while(iterator1.hasNext()){
// System.out.println(iterator1.next());
// }
for(Object col:coll){
System.out.println(col);
}
System.out.println("************************");
//遍历所有key-value集
Set entry=map.entrySet();
//方式一:enytrySet()
Iterator iterator2 = entry.iterator();
while (iterator2.hasNext()){
// System.out.println(iterator2.next());
Object obj = iterator2.next();
Map.Entry e=(Map.Entry) obj;
System.out.println(e.getKey() + "------>" + e.getValue());
}
System.out.println("************************");
//方式二:
Set setKey=map.keySet();//返回所有key构成的Set集合
Iterator iterator1 = setKey.iterator();
while(iterator1.hasNext()){
Object next = iterator1.next();
Object o = map.get(next);
System.out.println(next+ "==========" +o);
}
}
}
Map实现类之一:HashMap
HashMap是 Map 接口使用频率最高的实现类。
允许使用null键和null值,与HashSet一样,不保证映射的顺序。
所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写: equals()和hashCode()
所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()
一个key-value构成一个entry
所有的entry构成的集合是Set:无序的、不可重复的
HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true, hashCode 值也相等。
HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。
HashMap的存储结构
JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)
JDK 8版本发布以后:HashMap是数组+链表+红黑树实现。
HashMap底层实现原理(以jdk7为例)
HashMap map=new HashMap();
在实例化后,底层创建了长度为16的一维数组 Entry[] table
......(可能已经执行了许多put()操作)
map.put(key,value);
首先,调用key所在类的hashCode()计算出key的哈希值,此哈希值在经过某种算法之后得到了Entry数组在内存中的位置;
1)如果此位置上的数为空,则此时key-value添加成功(情况一)
2)如果此位之上的数不为空,则意味着此位之上已经存在一个或多个数据(以链表形式存在),比较key和已经存在的一个或多个数据的哈希值:
--2.1如果key的哈希值和已经存在的数据的哈希值不同,则此时key-value添加成功(情况二)
--2.2如果key的哈希值和已经存在的数据的哈希值相同,则调用key所在的类的equals()方法继续进行比较:
--2.2.1若equals()返回false,则添加不成功
--2.2.2若equals()返回true,则添加成功(情况三)
补充:关于情况二和情况三:此时key-value和原来的数据以链表形式存储
在添加过程中,会涉及扩容问题,当超出临界值是(且要放得位置非空),默认扩容方式:扩容为原来的2倍,并将原数组数据复制过来
jdk8相较于jdk7在底层实现方面的不同
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk8中底层数组是Node[],而非Entry[]
3.首次调用put()方法时,底层创建长度为16的数组
4.jdk7中底层结构只有数组+链表;jdk8中底层结构为数组+链表+红黑树;
当数组的某一个索引位置上的元素以链表形式存在的属于个数>8,且当当前数字组长度>64是,此时的索引位置上的数据改为红黑树存储
HashMap源码中的重要常量
HashMap何时进行扩容
当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数 size)*loadFactor(填充因子)时 , 就 会 进 行 数 组 扩 容 , loadFactor 的默认 值 (DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中元素个数 超过16*0.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把 数组的大小扩展为 2*16=32,即扩大一倍
Map实现类之二:LinkedHashMap
LinkedHashMap 是 HashMap 的子类
在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代 顺序:迭代顺序与 Key-Value 对的插入顺序一致
LinkedHashMap底层使用结构与HashMap相同,因为LinkedHashMap继承于HashMap
区别:LinkedHashMap内部用Entry[]去替换Node[]
Map实现类之三:TreeMap
TreeMap存储 Key-Value对时,需要根据 key-value 对进行排序。
TreeMap 可以保证所有的 Key-Value 对处于有序状态。
TreeMep底层使用红黑树结构存储数据
TreeMap 的 Key 的排序:
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。
Map实现类之四:Hashtable
Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap, Hashtable是线程安全的。
Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。
与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value
与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
Map实现类之五:Properties
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法
HashMap、LinkedHashMap、TreeMap、Hashtable、Properties区别
HashMap:作为Map的主要实现类,线程不安全,效率高,存储null的key和value
LinkedHashMap:保证遍历Map元素时,可以按照添加元素的顺序实现遍历(在原有的HashMap底层结构上,添加了一对指针,指向前一个、后一个元素;对于频繁的遍历操作,此类执行效率高于HashMap)
TreeMap:保证按添加的key-value进行排序;此时考虑key的自然排序和定制排序;底层使用红黑树进行排序结构
HashTable:作为古老实现类,线程安全,效率低,不能存储null的key和value
Properties:常用来处理配置文件,可由和value都是String类型