繁体   English   中英

List 接口和 ArrayList 类:ensureCapacity() 和 trimToSize() 方法

[英]List Interface and ArrayList Class: ensureCapacity() and trimToSize() methods

我正在创建两个Arraylist ,然后我想应用ensureCapacity()trimToSize() ,但是

ArrayList<String> arrayList = new ArrayList<>();
arrayList.trimToSize();
arrayList.ensureCapacity(100);

List<String> list = new ArrayList<>();
list.trimToSize();
list.ensureCapacity(100);

当我从 Class 创建Arraylist时,我可以这样做。

当我使用List接口创建Arraylist时,我不能。

你能告诉我为什么会这样吗?

我查看了 Javadoc,发现只有ArrayList具有ensureCapacity()trimToSize()方法。

但是为什么当我从List接口创建ArrayList时不能在我的 ArrayList 上使用它们呢?

trimToSize()ensureCapacity()方法都只在ArrayList类中可用。

List接口中没有这样的方法。

原因是:这些方法旨在更改底层数组的大小。 trimToSize()创建一个长度等于列表大小的新数组,并且ensureCapacity()将创建一个给定长度的新底层数组。

这些方法对没有数组支持的LinkedList没有意义,因此它们没有在List接口中声明。

还值得指出的是,应该谨慎使用trimToSize() ,因为您可以创建一个循环或连续增长和修剪,而ArrayList的性能会非常糟糕。

考虑一下:大约50%的元素已从您的ArrayList中删除,您可以使用trimToSize()释放这个未占用的堆空间。 将创建一个小两倍的新底层数组,并将所有现有元素复制到其中。 但是随着下一个添加项ArrayList将再次变大两倍(这意味着应该在内存中分配一个新数组,并且应该将所有元素复制到其中)。 听起来性能不是很好。

一般来说, trimToSize()可能值得了解,因为它是 JDK 的一部分,并且因为有人可能会问你这个问题,例如在面试中。 但你永远不会使用它。

但是为什么当我从List接口创建ArrayList时不能在我的 ArrayList 上使用它们呢?

当变量是List类型时,您只能使用在 list 接口中声明的方法。 引用的类型定义了您如何与对象进行交互。 引用本身不是对象。 而且它无论如何都不会改变对象,你的ArrayList仍然是一个ArrayList 引用类型List定义了与对象(仍然是ArrayList )交互的方式。

为了访问未在List接口中定义的方法,您可以强制转换它:

List<String> list = new ArrayList<>();

ArrayList<String> list2 = (ArrayList) list;
list2.trimToSize();
list2.ensureCapacity(100);

但请注意,这种转换是不安全的,只有当变量list指向ArrayList而不是LinkedList时,它才会成功。 正如我之前所说,使用这些方法是可以的,但将来你几乎不需要它们。

我认为 Java 缺少一些重要的东西。 你说:

当我从类中创建ArrayList时,我可以这样做。

当我使用List接口创建ArrayList时,我不能。

这是不正确的。 在这两种情况下,您都在使用new ArrayList<>()创建一个ArrayList 这两个对象的创建方式完全相同。

两个版本之间的区别在于创建ArrayList对象之后会发生什么。

ArrayList<String> arrayList = new ArrayList<>();

将新对象分配给类型为ArrayList<String>的变量,但是

List<String> list = new ArrayList<>();

将新对象分配给类型为List<String>的变量。

不同之处在于各个变量的类型......而不是对象的类型。

  • 对于arrayList ,编译器知道变量引用的对象将是ArrayListArrayList的子类型。 因此它知道该对象将支持ArrayList和/或其超类定义的所有方法。 这包括ArrayList.trimToSize()

  • 对于list ,编译器知道变量中的对象是某个实现List接口的类。 所以它只知道它在List API 中有方法。 编译器知道对象实际上是ArrayList还是LinkedList还是CopyOnWriteList或任何其他实现List的类。 所以不在List API 中的方法不能应用到它。

    因此编译错误。


但是为什么当我从 List 接口创建ArrayList时不能在我的 ArrayList 上使用它们呢?

(你没有......见上文。)

因为您将ArrayList对象分配给List变量,所以您对编译器说:

“忘记这是一个ArrayList 。把它想象成一个List 。”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM