java Map集合总结

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


一、HashMap

Java中针对hash表采用的是链地址法(拉链法)提供的实现,key决定数据的存放位置

  • static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 初始化容积
  • static final float DEFAULT_LOAD_FACTOR = 0.75f;加载因子值,取值范围为0-1,扩容的上限值为容积*加载因子
  • static final int TREEIFY_THRESHOLD = 8;树化处理的阈值,当一个单向链上的元素个数>8时会自动从单向链转换为红黑树
  • static final int UNTREEIFY_THRESHOLD = 6;退化阈值,当一个红黑树上的节点数<6时,将自动从红黑树退化为链表

数据的具体存放方式为【数组+单向链/红黑树】

构造器相关:

  • 设置Map构建的相关参数,并不会直接初始化数组。默认初始化容积为16,加载因子为0.75
  • 如果构建HashMap时传入初始化容积值,并不是按照传入参数直接设定,而是转换大于等于用户参数的2的n次方值,例如传入11,实际上初始化值为16
  • 数据的具体存放的桶位置=经过扰动计算后的hash%容积

HashMap底层采用的是Entry数组【Map接口中提供了Entry接口的定义,HashMap中提供了Entry接口的实现Node和TreeNode】和链表/红黑树实现。

Map主要用于存储键key值value对,根据键得到值,因此键不允许重复,但允许值重复。

要求作为key值的类型必须提供hashCode和equals方法的实现,不能依靠从Object继承来的方法

HashMap是一个最常用的Map,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

HashMap最多只允许一条记录的键为null;允许多条记录的值为null

HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致,可能会出现环形链【JDK1.7】。如果需要同步,可以用 Collections的

synchronizedMap方法使HashMap具有同步的能力。

JDK8+插入数据到链表的最后面,Java7是插入到链表的最前面

二、Hashtable

Hashtable:线程安全的,不允许null的键或值;是线程安全的,但是Hashtable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁。多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差

1、Hashtable不允许null值或者null键,编译时不会报错,但是运行报错。HashMap允许null值或者null键,只是key为null只能一次,value为null没有限制

2、HashMap的实现上没有同步约束,但是Hashtable的实现方法上有synchronized同步约束,所以说Hashtabe属于一个线程安全的类

Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。通过拉链法实现的哈希表

Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。

具体数据存放还是拉链法,也有加载因子参数,默认容积值为11,默认加载因子为0.75,允许设置初始化容积值,默认加载因子为0.75,

HashMap是在第一次使用时才进行数组的初始化操作 ,扩容阈值=(int)(初始化容积*加载因子)

添加元素采用的是头插法

扩容操作的实现,新数组的容积为原始容积*2+1

三、Properties

类定义:

public class Properties extends Hashtable<Object,Object> {}

提供了读写配置文件.properties(后缀不绝对)的方法和持有key/value的配置信息
Properties文件的定义 abc.properties

# rules:    key=value
abc.name=zhanshan
abc.age=13

在properties文件中只能存放ascii码字符,不能直接存放多字节编码的字符。在IDE工具中直接配置中文,IDE会使用插件将输入的中文转换为unicode编码形式存放。实际上JDK工具提供了命令行工具native2ascii

读取并解析properties文件的方法

public class Work03 {
    public static void main(String[] args) throws Exception{
        Properties ps =new Properties();
        InputStream is =Work03.class.getResourceAsStream("abc.properties");
        ps.load(is);
        String name =ps.getProperty("abc.name");
        System.out.println(name);


    }
}

写出properties配置文件的方法

 ps.setProperty("abc.score","1234");
 ps.setProperty("abc.aaa","2333");
 ps.list(new PrintStream(new FileOutputStream("aaa.properties")));

四、LinkedHashMap

类定义:

public class LinkedHashMap<K,V>extends HashMap<K,V>implements Map<K,V>{}

额外引入链表可以存放添加元素的顺序,允许在遍历时以添加的顺序遍历输出

五、TreeMap

内部实现为红黑树,不是hash表,要求key值必须可比较或者自定义传入比较器

public class TreeMap<K,V>extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{}

六、Map实现类的比较

HashMap的存入顺序和输出顺序无关。Key值对象 hashCode和equals方法

LinkedHashMap则保留了键值对的存入顺序,一般不会使用访问顺序。Key值对象 hashCode和equals方法

LinkedHashMap虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序

TreeMap则是对Map中的元素进行排序。要求key实现Comparable接口或者创建TreeMap时设置对应的比较器(Comparator接口的实现),注意和hashcode以及equals无关

上一篇:ConcurrentHashMap允许一边遍历一边更新,而用HashMap则会报线程安全问题


下一篇:LeetCode笔记(1)