集合接口与数组

kre*_*ker 43 java collections

我们正在了解收集界面,我想知道你们是否对它的一般用途都有任何好的建议?对于不能用数组做的Collection,你能做些什么?你怎么能用一个你不能用Collection做的数组(除了允许重复)?

Kev*_*ion 66

如果您这样想的话很容易:集合在基本上每种可以想象的方式都优于对象数组.

你应该更喜欢List<Foo>Foo[]只要有可能.考虑:

  • 集合可以是可变的或不可变的.非空数组必须始终是可变的.
  • 集合可以是线程安全的; 甚至并发.发布到多个线程永远不会安全.
  • 集合可以允许或禁止null元素.数组必须始终允许null元素.
  • 集合是类型安全的; 数组不是.因为数组"假"协方差,ArrayStoreException可以在运行时产生.
  • 集合可以保持不可再生类型(例如List<Class<? extends E>>List<Optional<T>>).使用数组,您将收到编译警告和混乱的运行时异常.
  • 一个集合有一个完全充实的API; 数组只有set-at-index,get-at-index和length.
  • 一个集合可以有视图(不可修改,子列表,过滤器......).数组没有这样的运气.
  • 列表或设置的equals,hashCodetoString方法做什么用户的期望; 阵列上的那些方法可以做任何事情,除了你期望的 - 一个常见的bug来源.
  • 由于上述所有原因,像Guava这样的第三方库不会为数组添加额外的支持,只关注集合,因此存在网络效应.

对象数组永远不会成为Java中的一等公民.

从第119页开始,Effective Java,Second Edition中更详细地介绍了上述一些原因.

那么,为什么你会使用对象数组呢?

  • 您必须与使用它们的API进行交互,并且无法修复该API
    • 所以转换为/ List尽可能接近API
  • 您有一个可靠的基准测试,表明您实际上已经获得了更好的性能
    • 但是基准测试可以说谎,而且通常都会存在
  • 我想不出任何其他原因

  • 根据我的理解,在不同线程访问数组的不相交部分的情况下,数组本质上是线程安全的,而不会锁定.对于与任何写入并发的任何操作,大多数集合都不是线程安全的,即使被执行的区域是不相交的,或者即使所有线程碰巧访问不相交的区域,它们也会产生大量与线程相关的开销.在.net数组中,即使线程使用共享元素,也可以通过`Interlocked.CompareExchange`提供线程安全性,但我不认为Java数组元素可用. (2认同)

aio*_*obe 7

这基本上是所需抽象级别的问题.

大多数集合可以用数组实现,但为方便起见,它们提供了更多的方法.例如,我所知道的大多数集合实现可以根据需求增长和缩小,或者执行基本数组无法执行的其他"高级"操作.

例如假设您正在从文件加载字符串.您不知道文件包含多少个换行符,因此您不知道在分配数组时要使用的大小.因此,ArrayList是更好的选择.


Liv*_*Liv 0

Collection 接口只是专门集合的基接口——我还不知道有一个类只是实现 Collection;相反,类实现扩展 Collection 的专用接口。这些专门的接口和抽象类提供了处理集合(唯一对象)、增长数组(例如ArrayList)、键值映射等的功能——所有这些都不能用数组直接完成。然而,迭代数组以及设置/读取数组中的项目仍然是 Java 中处理数据最快的方法之一。