Java集合类之---(Map集合)

Map集合

  • Map集合中会一次性保存两个对象,且这两个对象的关系:key=value结构;这种结构最大的特点是可以通过key找到对应的value内容
  • Map接口定义:public interface Map<K,V>
  • Map接口中常用方法
NO方法名称类型描述
1public V put(K key,V value)普通向Map中追加数据
2public V get(Object key)普通根据key取得对应的value,如果没有,返回null
3public Set< K>keySet()普通取得key信息,key信息不能重复
4public Collection< V>values()普通取得所有value信息,可以重复
5public Set<Map,Entry<K,V>> entrySet()普通将Map集合变为Set集合
  • Map本身是一个接口,要使用Map需要通过子类进行对象实例化。
  • Map接口的常用子类有如下四个: HashMap、Hashtable、TreeMap、ConcurrentHashMap
HashMap子类
  • HashMap 内部的结构,可以看作是数组(Node[ ] table)和链表结合组成的复合结构,数组被分为一个个桶(bucket),通过哈希值决定了键值对在这个数组的寻址;哈希值相同的键值对,则以链表形式存储
  • key可以为null;key不能重复,如果重复,相当于覆盖
  • value可以重复;value可以为null
 Map<Integer,String> map = new HashMap<>();
        map.put(1,"A");
        map.put(2,"B");
        map.put(3,"C");
        // key重复
        map.put(1,"B");
        System.out.println(map);
        // 根据key取得value
        System.out.println(map.get(2));
        // 查找不到返回null
        System.out.println(map.get(99));
  • 取得Map中所有key信息
 Map<Integer,String> map = new HashMap<>();
        map.put(1,"A");
        map.put(2,"B");
        map.put(3,"C");
        map.put(1,"B");
       Set<Integer> set = map.keySet();
       Iterator<Integer> iterator = set.iterator();
       while (iterator.hasNext()){
           System.out.println(iterator.next());
       }
  • entrySet()遍历Map;keySet()和get()共同也可以遍历
  • 默认初始容量(16),默认负载系数(0.75)
  • 如果链表大小超过阈值(TREEIFY_THRESHOLD, 8),图中的链表就会被改造为树形结构。
    在这里插入图片描述
  • 找到HashMap的源码,就会发现:HashMap 按照 lazy-load 原则,在首次使用时被初始化;如果表格是 null,resize 方法会负责初始化它;resize 方法兼顾两个职责,创建初始存储表格,或者在容量不满足需求的时候,进行扩容(resize)
  • 门限值等于(负载因子)*(容量),如果构建 HashMap 的时候没有指定它们,那么就是依据相应的默认常量值
  • 门限通常是以倍数进行调整 (newThr = oldThr << 1),我前面提到,根据 putVal 中的逻辑,当元素个数超过门限大小时,则调整Map 大小
  • 扩容后,需要将老的数组中的元素重新放置到新的数组,这是扩容的一个主要开销来源
  • 所以,总结:HashMap延迟初始化;当链表的节点超过8,桶的个数超过64,就会把桶数组树化;当前负载因子大于(默认负载因子*16)或链表节点个数<8,数组长度没有超64,就会扩容操作
HashTable子类
  • Hashtable是最早实现这种二元偶对象数据结构
  • key和value都不能为null
Map<Integer,String> map = new Hashtable<>() ;
map.put(1,"hello") ;
// key重复
map.put(1,"Hello") ;
map.put(3,"Java") ;
map.put(2,"Bit") ;
System.out.println(map);
HashMap与Hashtable的区别
  • 二者使用上基本一致
NO区别HashMapHashTable
1推出版本JDK1.2JDK1.0
2性能异步处理,性能高同步处理,性能较低
3安全性非线程安全线程安全
4null操作允许存放null(有且只有一个)key与value都不为空,否则出现NullPointerException
ConcurrentHashMap子类
  • 总体结构上,它的内部存储变得和HashMap 结构非常相似,同样是大的桶(bucket)数组,然后内部也是一个个所谓的链表结(bin),同步的粒度要更细致一些;
  • 其内部仍然有 Segment(分段) 定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处;
  • 因为不再使用 Segment,初始化操作大大简化,修改为 lazy-load 形式,这样可以有效避免初始开销,解决了老版本很多人抱怨的这一点;
  • 数据存储利用 volatile 来保证可见性;
  • 使用 CAS 等操作,在特定场景进行无锁并发操作
  • 使用 Unsafe、LongAdder 之类底层手段,进行极端情况的优化
TreeMap子类
  • 一个可以排序的Map子类,它是按照Key的内容排序的;按照的是Comparable接口完成的;
  • 有Comparable出现的地方,判断数据就依靠compareTo()方法完成,不再需要equals()与hashCode();
Map集合小结
  • Collection保存数据的目的一般用于输出(Iterator),Map保存数据的目的是为了根据key查找,找不到返回
    null。
  • Map使用Iterator输出(Map.Entry的作用)
  • HashMap数据结构一定要理解(链表与红黑树)、HashMap与Hashtable区别
Map集合使用Iterator输出

在这里插入图片描述

  • Map接口里面有一个重要的方法,将Map集合转为Set集合public Set<Map.Entry<K, V>> entrySet()

  • Map要想调用Iterator接口输出,走的是一个间接使用的模式
    在这里插入图片描述

  • 通过Iterator输出Map集合

public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>() ;
map.put(1,"Hello") ;
map.put(2,"Bit") ;
map.put(3,"Java") ;
// 1.将Map集合转为Set集合
Set<Map.Entry<Integer,String>> set = map.entrySet() ;
// 2.获取Iterator对象
Iterator<Map.Entry<Integer,String>> iterator = set.iterator() ;
// 3.输出
while (iterator.hasNext()) {
// 4.取出每一个Map.Entry对象
Map.Entry<Integer,String> entry = iterator.next() ;
// 5.取得key和value
System.out.println(entry.getKey()+" = " +entry.getValue()) ;
}
}
关于Map中key的说明
  • 用户可以采用自定义类作为key;这个时候一定要记得覆写Object类的hashCode()与equals()方法
class Person {
private Integer age ;
实际开发来讲,我们一般都是采用系统类(String,Integer等)作为Key值,这些系统类都帮助用户覆写好了hashCode()
与equals()方法。
private String name ;
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(age, person.age) &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class TestDemo {
public static void main(String[] args) {
Map<Person,String> map = new HashMap<>() ;
map.put(new Person(15,"张三"),"zs") ;
System.out.println(map.get(new Person(15,"张三")));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值