Q:Java 中常用的集合有哪些?
Java 集合分为 Collection 和 Map
Collection
Colletion 包括 List、Set、Queue
List:有序集合,允许有重复元素,主要实现类有
- Vector:线程安全的动态数组
- ArrayList:与 Vector 类似,基于动态数组实现,支持随机访问,查询快,增删慢,因为要移动后续所有的元素,但它不是线程安全的,性能更好;底层都是使用对象数组保存数据,当数组满时,会自动扩容,创建新的数组,并拷贝原有数组数据,扩容后容量 ArrayList 增加 50%,Vector 增加一倍。
- LinkedList:基于双向链表实现,只能顺序访问,查询慢,增删快。
Set:是 Map 的马甲,和 List 最大的区别是,不允许有重复元素,主要实现类有
- HashSet:基于 HashMap 实现,底层创建了一个 Dummy 对象 “PRESENT” 作为 value,所有元素以键的形式放入 HashMap 中,即 HashSet 是以哈希算法来存储元素,所以散列正常时,能提供常数时间的 add、contain 操作,但不保证有序。
- LinkedHashSet:HashSet 的子类,基于 LinkedHashMap 实现,底层使用双向链表维护元素插入的顺序,同时能提供常数时间的 add、contain 操作,但性能略低于 HashSet,因为有需要维护链表的开销。
- TreeSet:基于 TreeMap 实现,支持顺序访问,默认按值升序,也可以由指定的 Comparator 来决定,但 add、contain 操作效率为 O(logN)。
Queue:主要实现类有
- LinkedList:用来实现栈、队列和双向队列。
- PriorityQueue:基于堆实现,可用来实现优先队列。
Map
Map 存储键值对,主要实现类有:
- Hashtable:基于哈希表实现,不支持 null 键和值,由于同步导致性能较差,不推荐使用。
- HashMap:与 Hashtable 类似,基于哈希表实现,但支持 null 键和值,并且不是线程安全的,性能更好;散列正常时,能提供常数时间的 put / get 操作,但不保证有序;如果需要满足线程安全,可以用 Collections.synchronizedMap() 使 HashMap 具备线程安全的能力,或者直接用性能更好的 ConcurrentHashMap。
- LinkedHashMap:HashMap 的子类,底层使用双向链表维护元素插入的顺序,也可以构造时设置 accessOrder 为 true,转换成访问顺序;同时能提供常数时间的 put / get 操作,但性能略低于 HashMap,因为有需要维护链表的开销。
- TreeMap:基于红黑树实现,支持顺序访问,默认按键值升序,也可以由指定的 Comparator 来决定,但 put / get 效率为 O(logN);使用时,key 必须实现 Comparable 接口或者在构造时传入指定的 Comparator,否则运行时会抛出 ClassCastException。
对于这些 Map,都要求 key 是不可变对象,确保创建后它的哈希值不变;
因为如果发生改变,Map 就可能定位不到映射的位置。