三者都是实现集合框架中的 List,也就是所谓的有序集合,所以功能比较类似,比如都提供按照位置进行定位、添加或者删除的操作,都提供迭代器以遍历其内容.因为具体的设计区别.在行为、性能、线程安全等方面,表现不同。
Vector 是 Java 早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的.Vector 内部是使用对象数组来保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有数组数据
ArrayList 是应用更加广泛的动态数组实现,它本身不是线程安全的,所有性能要好很多。与Vector 近似,ArrayList 也是可以根据需要调整容量,不过两者逻辑有所区别,Vector 在扩容时会提高 1 倍,而ArrayList 则是增加50%
LinkedList 顾名思义是Java提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的
- Vector 和 ArrayList 作为动态数组,内部顺序存储,非常适合随机访问场合,不适合插入和删除操作
- LinkedList 进行节点插入、删除却高效得多,但是随机访问性能则比动态数组慢
-
Java 集合框架的设计结构,至少要有一个整体印象。
-
Java 提供的主要容器(集合和 Map)类型,了解或掌握对应的数据结构、算法,思考具体技术选择。
-
将问题扩展到性能、并发等领域。
-
集合框架的演进与发展。
-
内部排序
,至少掌握基础算法如归并排序、交换排序(冒泡、快排)、选择排序、插入排序 等。 -
外部排序
,掌握利用内存和外部存储处理超大数据集,至少要理解过程和思路。 -
排序的稳定性
-
List,也就是我们前面介绍最多的
有序集合
,它提供了方便的访问、插入、删除等操作。 -
Set,Set 是
不允许重复元素
的,这是和 List 最明显的区别,也就是不存在两个对象 equals返回 true。我们在日常开发中有很多需要保证元素唯一性的场合。 -
Queue/Deque,则是 Java 提供的标准队列结构的实现,除了集合的基本功能,它还支持类 似先入先出(FIFO, First-in-First-Out)或者后入先出(LIFO,Last-In-First-Out)等特定 行为。这里不包括 BlockingQueue,因为通常是并发编程场合,所以被放置在并发包里。
每种集合的通用逻辑,都被抽象到相应的抽象类之中,比如 AbstractList 就集中了各种 List 操 作的通用部分。这些集合不是完全孤立的,比如,LinkedList 本身,既是 List,也是 Deque 哦。
如果阅读过更多源码,你会发现,其实,TreeSet 代码里实际默认是利用 TreeMap 实现的, Java 类库创建了一个 Dummy 对象“PRESENT”作为 value,然后所有插入的元素其实是以键 的形式放入了 TreeMap 里面;同理,HashSet 其实也是以 HashMap 为基础实现的,原来他 们只是 Map 类的马甲!
-
TreeSet 支持自然顺序访问,但是添加、删除、包含等操作要相对低效(log(n) 时间)。
-
HashSet 则是利用哈希算法,理想情况下,如果哈希散列正常,可以提供常数时间的添加、 删除、包含等操作,但是它不保证有序。
-
LinkedHashSet,内部构建了一个记录插入顺序的
双向链表
,因此提供了按照插入顺序遍历 的能力,与此同时,也保证了常数时间
的添加、删除、包含等操作,这些操作性能略低于 HashSet,因为需要维护链表的开销。 -
在遍历元素时,HashSet 性能受自身容量影响,所以初始化时,除非有必要,不然不要将其背后的 HashMap 容量设置过大。而对于 LinkedHashSet,由于其内部链表提供的方便,遍历性能只和元素多少有关系。
在 Java 8 之中,Java 平台支持了 Lambda 和 Stream,相应的 Java 集合框架也进行了大范围的增强,以支持类似为集合创建相应 stream 或者 parallelStream 的方法实现,我们可以非常方便的实现函数式代码。
阅读 Java 源代码,你会发现,这些 API 的设计和实现比较独特,它们并不是实现在抽象类里面,而是以默认方法的形式实现在 Collection 这样的接口里!这是 Java 8 在语言层面的新特性,允许接口实现默认方法,理论上来说,我们原来实现在类似 Collections 这种工具类中的方 法,大多可以转换到相应的接口上。针对这一点,我在面向对象主题,会专门梳理 Java 语言面向对象基本机制的演进。
在 Java 9 中,Java 标准类库提供了一系列的静态工厂方法,比如,List.of()、Set.of(),大大简 化了构建小的容器实例的代码量。根据业界实践经验,我们发现相当一部分集合实例都是容量非常有限的,而且在生命周期中并不会进行修改。但是,在原有的 Java 类库中,我们可能不得不 写成:
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
而利用新的容器静态工厂方法,一句代码就够了,并且保证了不可变性。
List<String> simpleList = List.of("Hello","world");