为什么数组的长度是不可变的?

时间:2013-11-15 18:00:25

标签: java arrays

为什么数组的长度是不可变的(至少在java中)?我对编程语言的内部工作几乎一无所知,所以对我来说似乎很容易使数组的长度发生变化。我假设数组长度有一个很好的理由是不可变的,可能与性能有关。有人知道这个原因吗?

很抱歉,如果之前已经提出这个问题。如果有,我在大约10分钟的搜索中找不到它。

编辑:我知道当一个数组被初始化时,会分配一定数量的内存。为什么不能分配更多内存?

8 个答案:

答案 0 :(得分:9)

这个问题的实质在于语言设计者如何选择划分语言需要执行的任务,并将它们分配给不同的结构。

在Java中,标准数组类型具有固定长度,因为它旨在成为开发人员可以构建的低级别,简单的实现。

相反,如果您想要一个功能更全面的数组,请查看ArrayList<>类。我们的想法是为开发人员提供各种工具选择,这样您就可以随时选择适合自己工作的东西。

在谈论数组时,允许可变长度数组所需的机制非常重要。所以Java的创建者选择将这个功能放在ArrayList<>类中,而不是为那些只想要一个简单数组的人提供强制性开销。

为什么延长阵列非常重要?计算机内存是有限的,因此我们必须将对象彼此相邻存储。如果要延长阵列,如果附近的内存地址中已经存在另一个对象,该怎么办?

在这种情况下,没有足够的空间来就地延长阵列,因此必须移动数据以腾出空间。通常这是通过找到一个更大的空白内存块并在延长它的同时复制数组来完成的。如何以尽可能最好的方式做到这一点的数学(例如,留下多少空的空间?)是有趣且不平凡的。 ArrayList<>为您抽象了这个过程,因此您不必自己处理它,并且您可以确信ArrayList<>类的设计者选择了一个性能良好(平均)的实现你的申请。

答案 1 :(得分:5)

与表现无关。长度是分配的大小。您无法更改创建时已设置的内容。大小是实际分配的空间量,您也无法更改它。

您可以做的是获取不同大小的数组副本。

答案 2 :(得分:4)

Oracle's Java Array tutorial中所述:

  

数组是一个容器对象,它包含固定数量的单个类型的值。创建数组时,将建立数组的长度。创建后,其长度是固定的。

由于结构本身,长度是固定的。定义一个时,指定必须为其分配内存量的一定数量的元素。

如果您必须“调整”数组,则必须创建具有更大容量的数组并将现有元素复制到该数组。有很多方法可以做到这一点。


修改

创建数组时,会分配一定量的内存,足以存储所需实例的数量(基元的值,对象的引用)。调整数组大小意味着扩展该内存块,并且无法保证它是连续的。

答案 3 :(得分:2)

可以实现数组类型以提供以下任何两个:

  • 调整数组大小并引用旧数组的能力成为对新数组的引用

  • 多线程同时独立地操作数组的能力,没有锁定或其他类似的措施,只提供没有两个线程尝试写入数组的相同部分,并且任何线程读取部分在另一个线程中编写的数组可以正常使用旧数据或新数据。

  • 使用单个而非双向或三个间接的数组元素访问。

虽然可以构造数组类型,以便允许对给定大小的数组的引用成为对不同大小的数组的引用,但是数组将失去大部分线程安全性。可以肯定的是,只有在调整数组大小时写入数组数据时才会出现问题,但是如果不使用锁来保护对阵列的所有写入,就没有很好的方法来防范这种可能性,从而大大增加了它们的成本。

作为替代方案,可以让数组包装器保存对元素引用数组的引用,而不是直接保存元素,在这种情况下,可以通过锁定来复制数组,从而复制所有元素引用数组到一个更大的数组,分配新对象来保存新元素并将引用放在新数组中,更新数组引用,使其指向新数组,并释放锁。锁只是防止同时调整大小的必要条件。元素读取和写入可以在没有锁定的情况下正常进行,因为旧和新数组中存在的每个元素都将保证在两者中都相同[即两者都将保持对同一对象的引用,并且数组写入不会更改存储在任一数组中的引用,而是会修改由这些引用标识的对象]。除了调整数组大小之外,这种方法可以避免执行任何类型的锁定,但遗憾的是,在访问任何数组元素时需要过多的工作。

在设计.NET和Java的数组类型时,实现者认为上面的第一个特征是最不重要的,因此专注于提供另外两个特征。

答案 4 :(得分:1)

有些编程语言实际上允许这样做,比如VB.net的redim函数。使用Java,C / C ++等,它可以用其他数据结构来解释,例如向量和链表。

除此之外,当元素存储在一个数组中时,它们是连续存储的(一个接一个),所以要调整它的大小,在幕后为支持它开箱即用的语言做了什么,是一个新的数组实际上是由新大小创建的,内容被转储到它中(在VB.net的情况下,你必须明确告诉它复制原始内容,iirc)。让数组在运行中可调整大小的真正问题是你需要提前知道数组可能获得多大的数量,因此可以分配适当数量的连续内存来存储所有元素。

答案 5 :(得分:1)

这是一个设计选择。它不是关于Java在内部工作的方式,而是关于让程序员更自由地仅使用他们需要的资源。

变量长度集合,如ArrayList,带有几个方法,指针和开销。如果你的数据不会很快改变大小,为什么你想要这个开销呢?

答案 6 :(得分:1)

Java支持具有不可变长度的数组和大小可以更改的ArrayList个对象。正如其他人所指出的那样,后者需要额外的开销;如果为一个数组分配了一定的大小,并且你后来想要把它做大,那么通常代码必须为更大的数组分配新空间并移动整个数组,或者ArrayList必须是用链接实现,这可以使它越来越慢,或者可能是两者的某种组合。所以这是一个权衡,你可以选择最适合你需求的那个。我所知道的只提供第二种数组(Perl,JavaScript,PHP)的语言都是解释语言,我认为,这意味着以这些语言运行程序本来就会变慢,无论如何;这可能是这些语言的设计者认为表现不太重要的原因。

答案 7 :(得分:1)

几乎任何语言的数组都有固定的大小。它与内存分配有关:当你告诉Java你想要一个大小为N的数组时,它会熄灭并分配一个连续的内存块。大小由N *(单个元素的大小)确定。尺寸无法改变的原因是因为无法保证存储器中阵列之前或之后的内容。要添加其他元素,您需要&#34;声明&#34;数组后直接在内存中的空间。但是,这可能已被其他东西使用。为了避免复杂性和开销,他们只是为了让你不能调整数组的大小。

您可以做的是分配一个更大尺寸的新数组并将所有旧元素复制到其中。这就是像ArrayList这样的数据结构的工作原理。

希望有所帮助