List& Set& Map
- ArrayList / LinkedList / Vector特点及比较
- ArrayList特点:
- LinkedList特点:
- Vector特点:
- Map
- HashMap / LinkedHashMap / TreeMap / Hashtable / Properties特点及比较
- HashMap特点:
- LinkedHashMap特点:
- TreeMap特点:
- Hashtable特点:
- Properties特点:
- HashSet / LinkedHashSet / TreeSet特点及比较
- HashSet特点:
- LinkedHashSet特点:
- TreeSet特点:
- Collections工具类
ArrayList / LinkedList / Vector特点及比较
ArrayList特点:
- 线程不安全
- 底层使用 Object[]存储
- 实例化时默认10个元素
插入(添加到元素与元素之间)和删除的操作效率很差
值加到末尾, 查询和遍历操作性能很好
LinkedList特点:
- 线程不安全
- 底层使用双向链表存储
插入(添加到元素与元素之间)和删除的操作效率很好
Vector特点:
- 线程安全
- 底层使用 Object[]存储
- 实例化时默认10个元素
* 由于性能原因, 现在基本不再使用 Vector, 即使需要线程安全也不会使用. 如需要则通过 ArrayList结合 Collections工具类中的 synchronizedList方法来实现
List list = Collections.synchronizedList(new ArrayList<>());
list.add(2);
list.add(4);
list.add(1);
synchronized (list) {
Iterator i = list.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
}
- ArrayList& Vector的区别:
-
两种集合实例化时, 都默认生成10个元素
. 区别为 Vector(jdk7& 8)是会直接开辟10个元素(类似于单例的饿汉式), 而 ArrayList(jdk8)是只会赋予 {}, 也就是未直接开辟10个元素的内存空间当添加新值时才会真正创建数组
(类似于单列的懒汉式), 不过 ArrayList(jdk7)也是直接开辟 -
每当扩容时 Vector是默认2倍, 而 ArrayList是1.5倍
(原有长度 + (原有长度 >> 1 向右移一位等同除以2))
- 基本使用
ArrayList arrayList = new ArrayList();
arrayList.add(2);
arrayList.add(4);
arrayList.add(1);
arrayList.add(1, 100); // 插入
System.out.println(arrayList); // [2, 100, 4, 1]
arrayList.set(2, 200); // 覆盖
System.out.println(arrayList); // [2, 100, 200, 1]
arrayList.addAll(1, Arrays.asList(300, 400)); // 插入
System.out.println(arrayList); // [2, 300, 400, 100, 200, 1]
arrayList.addAll(Arrays.asList(new int[] {111, 222})); // 当一个元素添加
System.out.println(arrayList); // [2, 300, 400, 100, 200, 1, [I@1540e19d]
arrayList.addAll(Arrays.asList(new Integer[] {333, 444})); // 按多个元素添加
System.out.println(arrayList); // [2, 300, 400, 100, 200, 1, [I@1540e19d, 333, 444]
System.out.println(arrayList.indexOf(400)); // 2
System.out.println(arrayList.lastIndexOf(999)); // -1
System.out.println(arrayList.subList(1, 3)); // [300, 400]
arrayList.remove(2); // 指定索引
System.out.println(arrayList); // [2, 300, 100, 200, 1, [I@1540e19d, 333, 444]
arrayList.remove(new Integer(2)); // 指定值, 不是索引
System.out.println(arrayList); // [300, 100, 200, 1, [I@1540e19d, 333, 444]
# 迭代器
Iterator iter = arrayList.iterator();
while(iter.hasNext()) {
System.out.println(iter.next());
}
300
100
200
1
Map
- Map是用来保存有映射关系的数据(key-value), key和 value可以是任何引用类型的数据
HashMap / LinkedHashMap / TreeMap / Hashtable / Properties特点及比较
HashMap特点:
- 线程不安全
- key是用 Set来存放的, 即存储是无序的, 且不可重复(当 key为自定义 Java类, 且要按照属性的值来判断是否相等, 则需要覆写 equals方法和 hashCode方法)
- 可以存 null键& 值
- 键的存储是无序的
- 键不可重复
- 底层数组长度超过了临界值, 且要存放的位置非空时, 便会自动扩容(默认2倍)
- 自定义初始长度必须是2的多少次幂, 如: 设置了15, 会自动被改为16
- Jdk7及以前版本的特点:
(1) 实例化时默认创建16的一维数组类型 Entry[] table
(2) 存储结构是数组+链表: 当哈希冲突时
(-) 如果 Key相同, 则覆盖 value
(-) 会生成链表, 新 key存到数组的指定位置, 然后将之前的值(key)往下移存到链表中(存到链表的首个节点)- Jdk8较于之前的变化:
(1) 实例化时不会(默认)直接创建长度为16的数组, 而是在首次调用 put方法时, 便会真正创建16的数组 Node[] tab
(2) 存储结构是数组+链表+红黑树: 当哈希冲突时
(-) 如果 Key相同, 则覆盖 value
(-) 会生成链表, 将新 key存到链表中(存到链表的最后节点)
(-) 当数组的某一个索引位置上元素以链表形式存的数据个数已达到8个, 且当前数组长度已达到64时, 此索引位置上的所有数据会被变更为红黑树存储结构(数组长度小于64, 则会自动扩容)
(-) 当有映射关系被移除时, 内部 Resize方法, 会判断树的节点个数是否低于6个, 如果低于, 则会将红黑树再转换为链表存储结构
- 什么是负载因子?
负载因子决定 HashMap的数据密度(DEFAULT_LOAD_FACTOR=0.75f)
(-) 密度越大, 发生碰撞的几率就越高, 数组中的链表会越长.
(-) 密度越小, 发生碰撞的几率就越小, 数组中的链表会越短, 就越容易触发扩容- 什么是吞吐临界值?
threshold=32(当前容量)*0.75f(负载因子/DEFAULT_LOAD_FACTOR)
(-) 触发自动扩容的界限值
(-) 为什么 HashMap元素未填满就会扩容? 因为所有元素不一定能填满, 可能很多部分 key会一直发生碰撞产生链表和红黑树
- 基本使用
HashMap hashMap = new HashMap();
hashMap.put("A", 11);
hashMap.put("C", 33);
hashMap.put("B", 22);
hashMap.put("D", 44);
Object return01 = hashMap.remove("C"); // 删除并返回值
System.out.println(return01); // 33
boolean return02 = hashMap.containsKey("B"); // 是否包含指定键
System.out.println(return02); // true
boolean return03 = hashMap.containsValue(33); // 是否包含指定键
System.out.println(return03); // false
Set return04 = hashMap.keySet(); // 返回所有 key构成的 Set集合
System.out.println(return04); // [A, B, D]
Collection return05 = hashMap.values(); // 返回所有 value构成的 Collection集合
System.out.println(return05); // [11, 22, 44]
Set return06 = hashMap.entrySet(); // 返回所有 key-value对构成的 Set集合
System.out.println(return06); // [A=11, B=22, D=44]
LinkedHashMap特点:
- HashMap的子集
- 采用了哈希表和链表(双向链表)的结合, 随是存储无序, 但是遍历时是按插入的顺序输出
TreeMap特点:
- 根据 key进行排序
- Key不能为 null
- 存储是有序
(1) 自然排序: 值为自定义类时, 实现 Comparable接口, 覆写 compareTo方法
(2) 定制排序: 实现 Comparator接口, 定制排序条件; new TreeSet(new Comparator() {public int compare}), 当两种都有时, 会优先采用定制排序- 底层结构是红黑树的存储结构
- 查询速度比 List快
Hashtable特点:
- 线程安全
- 不可以存 null键& 值
- 其它与 HashMap基本相同
* 由于性能原因, 现在基本不再使用 Hashtable, 即使需要线程安全也不会使用. 如需要则通过 HashMap结合 Collections工具类中的 synchronizedMap方法来实现或者使用 CurrentHashMap
Properties特点:
- Hashtable的子集, 继承了 Hashtable的基本特性 如 线程安全等
- Key和 value都是 String类型
- 演示代码
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);
HashSet / LinkedHashSet / TreeSet特点及比较
HashSet特点:
- 线程不安全
- 可以存 null值
- 存储是无序的(无序不等于随机, 当存储数据时, 会使用 HashCode+算法计算下标来存到底层数组中)
- 不可重复的(值为自定义 Java类, 且要按照属性的值来判断是否相等, 则需要覆写 equals方法和 hashCode方法)
- 底层结构是 HashMap(实例化默认长度& 扩容机制等: 参考 HashMap)
LinkedHashSet特点:
- 作为 HashSet的子集, 基本特性 如: 线程不安全, 存 null值, 存储无序, 不可重复等相同
- 底层结构是 LinkedHashMap, 采用了哈希表和链表(双向链表)的结合, 随是存储无序, 但是遍历时是按插入的顺序输出
- 遍历效率高于 HashSet
TreeSet特点:
- 线程不安全
- 不能存 null值
- 不可重复
- 底层结构是 TreeMap, 基本特点相同
Collections工具类
- 基本使用
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(1);
Collections.reverse(list); // 反转 List中的元素顺序
System.out.println(list); // [1, 3, 2]
Collections.sort(list); // 自然顺序: 将 List集合元素按升序排序
// Collections.sort(list, Comparator); 定制排序
System.out.println(list); // [1, 2, 3]
Collections.swap(list, 2, 0); // 将指定 List集合中的 i处元素和 j处元素进行交换
System.out.println(list); // [3, 2, 1]
// Collections.shuffle(list); // 对 List集合元素进行随机排序
// System.out.println(list);
System.out.println(Collections.max(list)); // 返回指定集合中的最大元素
// System.out.println(Collections.max(list, Comparator)); 返回最大元素(指定条件)
System.out.println(Collections.min(list)); // 返回指定集合中的最小元素
// System.out.println(Collections.min(list, Comparator)); // 返回最小元素(指定条件)
list.add(2);
list.add(2);
System.out.println(list); // [3, 2, 1, 2, 2]
System.out.println(Collections.frequency(list, 2)); // 返回指定集合中指定元素的出现次数
List dest = Arrays.asList(new Object[list.size()]);
Collections.copy(dest, list); // 将 list(src)中的内容复制到 dest中
System.out.println(dest.size()); // 5
Collections.replaceAll(dest, 2, 4); // 将指定 List对象的所有旧值(oldVal), 替换为新值(newVal)
System.out.println(dest); // [3, 4, 1, 4, 4]
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!