以下没有特殊说明以jdk1.8为准
String、StringBuffer、StringBuilder
- String类型:实现了Serializable和Comparable接口,内部通过char[ ]实现,但其具有不可变性,对字符串重新赋值时,指针重新指向另一内存区域。
String str1 = "abc"
String str2 = new String("abc")
str1的值会存储在字符串常量池中,str2的值会先在堆中生成对象。
- StringBuffer和StringBuilder在底层同样使用char[ ]实现(JDK15 使用btye[ ]存储),但不同的它们是可变字符串序列,值改变时指针不会发送改变;
- StringBuffer线程安全的,使用synchronized同步锁实现,初始化数组长度为16
- StringBuilder线程不安全,初始化数组长度也为16
- 添加数据底层数组放不下时,默认情况下,扩容为原来容量2倍+2复制到新的数组中
HashMap、HashTable
- HashMap
- HashMap是Map的实现类,允许null键和null值HashTable则不允许;
- 所有key构成Set集合无序、不可重复,所有value构成Collection无序、可重复;
- 一个key-value构成一个Entry(jdk1.7)在jdk1.8中为Node;所有Entry构成Set集合,初始化为容量为16的Node[ ]在首次put元素时初始化
- 插入方式首先根据key的hashcode()算出散列值,通过散列值计算插入位置,如果该位置没有数据直接插入,如果该位置有数据再根据散列值判断是否有相同的元素,如果没有直接插入,如果有比较equals()查看是否相同,没有则插入,有则替换
- jdk1.7内部结构为数组+链表结构,采用头插法
- jdk1.8内部结构采用数组+链表+红黑树结构,采用尾插法
- 扩容为原来原来的2倍,之后调用resize()jdk1.7会重新计算所有数据的位置jdk1.8则不会
- 负载因子默认为0.75,扩容临界值为16*0.75=12
- 转为红黑树条件:链表长度>8 && 数组长度>64
- HashTable线程安全使用synchronized关键字实现
红黑树特点
- 一种带颜色的二叉查找树
- 每个节点要么是红色,要么是黑色,但是根节点永远是黑色
- 红色节点不能持续,红色节点的子和父都不能是黑色
- 从任一节点到其每个叶子节点的路径都是包含相同数量的黑色节点
HashSet、TreeSet、LinkedHashSet
- HashSet是Set接口的实现类,线程不安全,底层采用数组初始容量16,同样负载因子为0.75超过12会扩容为之前的2倍,底层采用数组+链表,扩容方式为原来的2倍,元素需要重写hashcode()和equals()
- TreeSet添加的元素需要实现自然排序接口Comparable或采用定制排序Comparator
- LinkedHashSet可以保证遍历时和插入时的元素顺序一致,因为里面采用双向链表结构维护元素次序
ArrayList、LinkedList、Vector
- ArrayList底层采用Object[ ]实现,和HashMap相同首次添加元素时初始化数据大小为10,扩容方式为原来的1.5倍。
- LinkedList底层采用双向链表实现。
- Vector jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组.在扩容方面,默认扩容为原来的数组长度的2倍。
ConcurrentHashMap
- 并发安全Map的数据结构
- jdk1.7中采用segment数据结构extend了ReentrantLock,每个segment内部还是采用数组+链表的hash结构,但是相较于HashTable锁住整个Map来说,锁的粒度更小,并发效果更好。
- 添加元素使用put方法,首先判断内部数组有没有初始化,没有则初始化数组;接着根据hash值计算数组下标,判断数组是否有值,没有则使用cas方式加入元素,有则使用synchronized将Node上锁,判断是链表结构还是红黑树结构采用不用的逻辑加入节点。