Vector、ArraysList和LinkedList有什么区别?

典型的回答

这三者都是集合框架中List的实现,也就是所谓的有序集合,它们在功能上比较近似。

Vector是Java早期提供的线程安全的动态数组,如果不需要线程安全,不建议选择。Vector内部是使用对象数组来保存数据,可以根据需要自动增加容量。当数据已满时,会创建新的数组,并拷贝原有数组数据。

ArrayList是应用更加广泛的动态数组实现,它不是线程安全的,所以性能要好很多。与Vector近似,ArrayList也可以根据需要调整容量,不过两者的调整逻辑有所区别,Vector在扩容时会提高1倍,而ArrayList则是增加50%。

LinkedList则采用了双向链表,所以它不需要像上面两者那样调整容量,它也不是线程安全的。相比之下,Vector与ArrayList的随机访问的性能要好于LinkedList,而LinkedList则在插入、删除操作却要高效得多。开发者可以据此作出选择。

知识扩展

1、集合框架的整体设计

作为常用的数据结构,开发者有必要对JDK的集合框架有所了解,为此画了个简要的类图。注意,为了避免混淆,没有加入java.util.concurrent中内容;也没有列出Map容器,虽然通常概念上我们也会把Map作为集合框架的一部分,但是它本身并不是真正的集合(Collection)。

可以看出Collection是所有集合的基础,在此基础上扩展出三大类集合:

  • List提供了有序集合,它提供了方便的访问、插入、删除等操作。
  • Set是不允许重复元素的,这是和List最明显的区别。也就是说不存在两个元素对象equals返回true。
  • Queue/Deque则是Java提供的标准队列结构的实现。除了集合的基本功能外,还支持类似先进先出(FIFO)或者后进先出(LIFO)等特定行为。

2、深入了解各种具体集合实现

有必要深入了解具体集合实现,至少了解其基本特征和典型使用场景。限于篇幅这里仅介绍Set的几个实现:

  • TreeSet支持自然顺序访问,但是添加、删除、包含等操作要相对低效(log(n)时间)。
  • HashSet则是利用哈希算法,理想情况下,如果哈希散列正常,可以提供常数时间的添加、删除、包含等操作,但是它不保证有序。
  • LinkedHashSet内部构建了一个记录插入顺序的双向链表,因此提供了按照插入顺序遍历的能力,与此同时,也保证了常数时间的添加、删除、包含等操作,这些操作性能略低于HashSet,因为需要维护链表的开销。
  • 在遍历元素时,HashSet性能受自身容量影响,所以初始化时,除非有必要,不然不要将其背后的HashMap容量设置过大。而对于LinkedHashSet,由于其内部链表提供的方便,遍历性能只和元素多少有关系。

3、线程安全

java.util中的集合类大部分都是线程不安全的,对于java.util.concurrent里面的线程安全容器,将在专栏后面去介绍。但是,并不代表这些集合完全不能支持并发编程的场景。在Collections工具类中,提供了一系列的synchronized方法,比如:

static <T> List<T> synchronizedList(List<T> list)

我们完全可以利用类似方法实现基本的线程安全集合:

List list = Collections.synchronizedList(new ArrayList());

它的实现,基本就是将每个方法,比如get、set、add之类,都通过synchronized添加基本的同步支持,非常简单粗暴,但也非常实用。注意这些方法创建的线程安全集合,都符合迭代时fail-fast行为,当发生意外的并发修改时,尽早抛出ConcurrentModificationException异常,以避免不可预计的行为。

4、排序

Arrays.sort()与Collections.sort()(底层是调用Arrays.sort())提供了默认排序算法。事实上Java几乎在每个版本都在排序问题上不断的改进。以Java 7为例:

  • 对于太小的数据库,复杂排序是没有必要的,Java会直接进行二分法插入排序。
  • 对于原始数据类型,使用的是所谓双轴快速排序(Dual-Pivot QuickSort),是一种改进的快速排序算法。据说最近双轴快速排序的作者又提交了一个更进一步的改进,目前正在审核和验证阶段。也许在未来的版本中就会体现。
  • 而对于对象数据类型,目前使用的是TimSort,思想上也是一种归并和二分插入排序(BinarySort)结合的优化排序算法。

另外,Java 8引入了并行排序算法,这是为了充分利用现代多核处理器的计算能力,底层实现基于fork-join框架,当处理的数据集比较小的时候,差距不明显,甚至还表现差一点;但是,当数据集增长到数万或百万以上时,提高就非常大了。

5、Java 8 与 9

Java 8对集合框架进行大范围的增强。特别引人注目的是引入了stream,结合Lambda表达式可以让一些代码变得更加简洁。例如以下代码实现了从一个字符串列表中找到最长字符串:

  public static Optional<String> getLongestString(List<String> ss) {
    return ss.stream().max(Comparator.comparing(String::length));
  }

在Java 9中,Java标准类库提供了一系列的静态工厂方法,比如,List.of()、Set.of(),大大简化了构建小的容器实例的代码量。根据业界实践经验,发现相当一部分集合实例都是容量非常有限的,而且在生命周期中并不会进行修改。

List<String> simpleList = List.of("Hello", "World");

猜你喜欢

转载自blog.csdn.net/qweqwruio/article/details/81332558
今日推荐