# Java集合

# 什么是泛型,有什么作用?

泛型本质是参数化类型,解决不确定对象具体类型的问题。泛型在定义处只具备执行 Object 方法的能力。

泛型的好处:① 类型安全,放置什么出来就是什么,不存在 ClassCastException。② 提升可读性,编码阶段就显式知道泛型集合、泛型方法等处理的对象类型。③ 代码重用,合并了同类型的处理代码。

# 泛型擦除是什么?

泛型用于编译阶段,编译后的字节码文件不包含泛型类型信息,因为虚拟机没有泛型类型对象,所有对象都属于普通类。例如定义 List<Object>List<String>,在编译后都会变成 List

定义一个泛型类型,会自动提供一个对应原始类型,类型变量会被擦除。如果没有限定类型就会替换为Object,如果有限定类型就会替换为第一个限定类型,例如 <T extends A & B> 会使用 A 类型替换 T。

# ArrayList和LinkedList有什么区别

  1. 是否保证线程安全: ArrayListLinkedList 都是不同步的,也就是不保证线程安全;
  2. 底层数据结构: Arraylist 底层使用的是 Object 数组LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受元素位置的影响:ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。
  4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  5. 内存空间占用: ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

# ★★★★★ HashMap、Hashtable、LinkedHashMap、TreeMap和WeakHashMap的区别与联系

HashMap是一个散列表,它存储的内容是键值对(key-value)映射。HashMap继承于AbstractMap,实现了Map、Cloneable、Serializable接口。HashMap的实现不是同步的,所以它不是线程安全的。它的Key、value都可以为null。此外,HashMap的映射不是有序的。JDK1.8之后,相同hash值的元素大于8时,存储结构由原来的链表变为红黑树。HashMap的默认容量大小为16,默认加载因子为0.75,当实际容量大于总量*加载因子时,每次将容量变为:原始容量*2。

Hashtable Java早期提供的接口,它是一个散列表,存储的内容是键值对(key-value)映射。Hashtable继承于Dictionary,实现了Map、Cloneable、Serializable接口。Hashtable的函数都是线程安全的,因此写入速度没有HashMap快。它的key、value都不可以为null。此外Hashtable中的映射不是有序的。Hashtable的默认容量大小为11,默认加载因子为0.75,当实际容量大于总量*加载因子时,每次将容量变为:原始容量*2+1。

LinkedHashMap拥有HashMap的所有特性,是一个由关联数组、哈希数组组成的的双向链表,保存了记录的插入顺序,因此LinkedHashMap是插入有序的(插入的自然顺序,数据的大小可能仍然是无序的)。它是线程不安全的,允许key、value为null,插入相同的key时自动覆盖。

TreeMap是通过红黑树实现的,获得一个元素的时间复杂度为log(n)。它是一个按照key存放的有序集合,默认是按照键值升序排序。TreeMap继承于AbstractMap,所以它也是一个key-value的键值对集合。

WeakHashMap的键是弱引用,而HashMap的键是强引用。WeakReference的"弱键"能实现WeakReference对"键值对"的动态回收。当"弱键"不再被引用到时,GC会回收它,WeakReference也会将"弱键"对应的键值对删除。这个"弱键"实现的动态回收"键值对"的原理,是通过WeakReference(弱引用)和ReferenceQueue(引用队列)实现的。在WeakHashMap中,"键"是WeakReference,即key是弱键。ReferenceQueue是一个引用队列,它是和WeakHashMap联合使用的。当弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

tips:一般的应用场景,尽可能多考虑使用HashMap,因为其为快速查询设计的。如果需要特定的排序时,考虑使用TreeMap。如果仅仅需要插入的顺序时,考虑使用LinkedHashMap。

最近更新: 12/3/2024
勤奋的凯尔森同学   |