目录
容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存 储着键值对(两个对象)的映射表。
一、Collection:
1、Set
Set 注重独一无二的性质,值不能重复,对象的相等性本质是对象 hashCode 值。
TreeSet:
基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1), TreeSet 则为 O(logN)。 Integer 和 String 对象都可以进行默认的 TreeSet 排序,而自定义类的对象是不可以的,自己定义的类必须实现 Comparable 接口,并且覆写相应的 compareTo()函数。
HashSet:
基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。 元素的哈希值是通过元素的hashcode 方法来获取的, HashSet 首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals 方法 如果 equls 结果为 true ,HashSet 就视为同一个元素。如果 equals 为 false 就不是同一个元素。HashSet 通过 hashCode 值来确定元素在内存中的位置。一个 hashCode 位置上可以存放多个元素。(链地址法)
LinkedHashSet:
具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。
2、List
ArrayList:
基于动态数组实现,支持随机访问。 缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
实现了 RandomAccess 接口,因此支持随机访问。数组的默认大小为10.
动态扩容特性
Vector:
和 ArrayList 类似,通过数组实现,但它是线程安全的。 支持线程的同步,即某一时刻只有一个线程能够写 Vector,但是实现同步的代价较高,访问会较慢。
LinkedList:
基于双向链表实现,只能顺序访问,但是可以快速地在链表中间 插入和删除元素,随机访问和遍历速度比较慢。不仅如此,LinkedList 还可以用作栈、队列和双向队列。
LinkedList与 ArrayList 的比较
ArrayList 基于动态数组实现,LinkedList 基于双向链表实现;
ArrayList 支持随机访问,LinkedList 不支持;
LinkedList 在任意位置添加删除元素更快。
3、Queue
LinkedList:
可以用它来实现双向队列。
PriorityQueue:
基于堆结构实现,可以用它来实现优先队列。
二、Map
TreeMap:
基于红黑树实现,可排序。实现 了SortedMap 接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的。
在使用 TreeMap 时,key 必须实现 Comparable 接口或者在构造 TreeMap 传入自定义的Comparator,否则会在运行时抛出 java.lang.ClassCastException 类型的异常。
HashMap( 数组+链表+红黑树):
基于哈希表实现。HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections 的 synchronizedMap 方法使HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。
拉链法:解决哈希冲突,即在相同哈希值的对应位置加上单链表,使用头插法。
HashTable:
和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。它是遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。
LinkedHashMap:
使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。
HashTable与HashMap区别:
HashTable 使用 synchronized 来进行同步。
HashMap 可以插入键为 null 的 Entry。
HashMap 的迭代器是 fail-fast 迭代器。
HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。
只是整理了JAVA集合的一些基本概念,更深入的源码分析,以后有能力有机会再完成吧!