目录
①Object put(Object key,Object value)
②boolean containsKey(Object key)
③boolean containsValue(Object value)
Map接口继承树
一、概述
Map:双列数据,存储key-value对的数据 (类似于高中讲解的函数)
(一)结构:
Map:双列数据,存储key-value对的数据 (类似于高中讲解的函数)
——HashMap:Map的主要实现类;线程不安全的,效率高;可以存储null的key和value
——————LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
(原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap)
————TreeMap:保证按照添加的key-value对进行排序,实现遍历排序。此时考虑key的自然排序或定制排序,底层使用红黑树
————HashTable:作为古老的实现类;线程安全的,效率低;不可以存储null的key和value
——————properties:常用来处理配置文件。key和value都是String类型
HashMap的底层
数组 + 链表(jdk 7及以前)
数组 + 链表 + 红黑树(jdk 8):效率得以提升
经典面试题:
①HashMap的底层实现原理?(以jdk 7为例说明)
HashMap map = new HashMap();
1.在实例化以后,底层创建了一个长度是16的一维数组Entry[ ] table
2.map.put(key1,value1)
3.首先,调用key1所在类的hashCode()计算哈希值,此哈希值经过某种算法计算以后,得到Entry数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1添加成功;
如果此位置上的数据不为空(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功;
如果key1的哈希值与已经存在的某一个数据的哈希值相同,继续比较:
调用key1所在类的equals()方法,比较:
如果equals()返回false——此时key1-value1添加成功;
如果equals()返回true——使用value1替换相同key的value值
关于后两种添加成功的说明:此时key1-value1和原来的数据以链表的方式存储
——在不断的添加过程中,会涉及到扩容问题
默认的扩容方式:扩容为原来的2倍,并将原有的数据复制过来
jdk 8相较于jdk 7在底层实现方面的不同
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk 8底层的数组:Node[ ]而非Entry[ ]
3.首次调用put()方法时,底层创建长度为16的数组
4.jdk 7底层结构只有数组 + 链表。jdk 8底层结构为:数组 + 链表 + 红黑树
当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8且当前数组的长度 > 64时,此时此索引位置上的所有数据改为使用红黑树存储。
②HashMap和HashTable 的异同?
主要的区别有:线程安全性,同步(synchronization),以及速度。
HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。
③CurrentHashMap和HashTable的区别?
HashMap是线程非安全的,效率比较高;HashTable和CurrentHashMap是线程安全的,效率比HashMap差一点,但CurrentHashMap比HashTable更加高效一些,因为CurrentHashMap采用了更加高效的分段锁机制。
(二)Map结构的理解
1.Map中的key
无序的,不可重复的,使用Set存储所有的key -----> key所在的类要重写equals()和hashCode() (以HashMap为例)
2.Map中的value
无序的,可重复的,使用Collection存储所有的value ----->value所在的类药重写equals()
3.Map中的entry
无序的,不可重复的,使用Set存储所有的entry
4.一个键值对
key-value构成了一个Entry对象
二、Map中的常用方法
1.添加、删除、修改操作:
①Object put(Object key,Object value)
Map map = new HashMap();
//添加
map.put("AA",123);
map.put(45,123);
map.put("BB",56);
//修改
map.put("AA",87);
System.out.println(map);
②void putAll(Map m)
Map map1 = new HashMap();
map1.put("CC",123);
map1.put("DD",123);
map.putAll(map1);
System.out.println(map); //{AA=87, BB=56, CC=123, DD=123, 45=123}
③Object remove(Object key)
Object value = map.remove("CC");
System.out.println(value); //123
System.out.println(map); //{AA=87, BB=56, DD=123, 45=123}
④void clear()
//clear
map.clear(); //与 map = null 操作不同
System.out.println(map); //{}
System.out.println(map.size()); //0
2.元素查询的操作
①Object get(Object key)
//Object get(Object key)
System.out.println(map.get(45)); //123
②boolean containsKey(Object key)
boolean isExist = map.containsKey("BB");
System.out.println(isExist); //true
③boolean containsValue(Object value)
isExist = map.containsValue(123);
System.out.println(isExist);
④int size()
map.clear(); //与 map = null 操作不同
System.out.println(map); //{}
System.out.println(map.size()); //0
⑤boolean isEmpty()
map.clear();
System.out.println(map.isEmpty()); //true
3.元视图操作的方法
①Set keySet()
//遍历所有的key集
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
②Collection values()
//遍历所有的value
Collection values = map.values();
for(Object obj : values){
System.out.println(obj);
}
③Set entrySet()
//遍历所有的key-value
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
// System.out.println(iterator1.next());
Object obj = iterator1.next();
//EntrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry)obj; //强制类型转换
System.out.println(entry.getKey() + "------>" + entry.getValue());
}
//方式二
Set keySet = map.keySet();
Iterator iterator2 = set.iterator();
while (iterator2.hasNext()){
Object key = iterator2.next();
Object value = map.get(key);
System.out.println(key + "=====" + value);
}
(两种方式遍历的结果)
三、向TreeMap中添加value
要求:key必须是由同一个类创建的对象
因为要按照key进行排序:自然排序 & 定制排序
1.自然排序
@Test
public void test1(){
TreeMap map = new TreeMap();
User u1 = new User("Tom",23);
User u2 = new User("Jerry",32);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,89);
map.put(u3,76);
map.put(u4,100);
//遍历所有的key-value
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
// System.out.println(iterator1.next());
Object obj = iterator1.next();
//EntrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry)obj; //强制类型转换
System.out.println(entry.getKey() + "------>" + entry.getValue());
}
}
2.定制排序
@Test
public void test2(){
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(), u2.getAge());
}
throw new RuntimeException("输入的类型不匹配");
}
});
User u1 = new User("Tom",23);
User u2 = new User("Jerry",32);
User u3 = new User("Jack",20);
User u4 = new User("Rose",18);
map.put(u1,98);
map.put(u2,89);
map.put(u3,76);
map.put(u4,100);
//遍历所有的key-value
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
// System.out.println(iterator1.next());
Object obj = iterator1.next();
//EntrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry)obj; //强制类型转换
System.out.println(entry.getKey() + "------>" + entry.getValue());
}
}