Java 为什么可以';数组不能调整大小吗?

Java 为什么可以';数组不能调整大小吗?,java,arrays,Java,Arrays,为什么不能动态地重新调整数组的大小,无论是基元数组还是其他数组 我知道您可以使用ArrayList,但它背后的实现仍然是一个初始大小的数组(我认为默认为50),当它超过50时,将创建一个新数组来包含这些元素 int[] arr = new int[10]; 因此,我试图理解使其不可分解的阵列的系统规范。要解决此问题,向量就在那里 使用向量就像动态分配内存。假设您定义了一个16字节的数组,一个整数&另一个整数 现在您希望调整它的大小 ===============================

为什么不能动态地重新调整数组的大小,无论是基元数组还是其他数组

我知道您可以使用
ArrayList
,但它背后的实现仍然是一个初始大小的数组(我认为默认为50),当它超过50时,将创建一个新数组来包含这些元素

int[] arr = new int[10];

因此,我试图理解使其不可分解的阵列的系统规范。

要解决此问题,向量就在那里


使用向量就像动态分配内存。

假设您定义了一个16字节的数组,一个整数&另一个整数

现在您希望调整它的大小

======================================================
|| || || || || || || || || || || || || || || || || ||   --->  (Memory)
======================================================
\________________/\____/\____/  
 ----------------  ----  ----
      Array(16)     Int  Int
上面的数组是否易于调整大小


必须为下一个可用的空闲内存块分配一个新数组,因为程序已经为整数保留了紧跟其后的块。

这是一个有效的问题,答案与计算机的实际工作方式有关


例如,当您使用
int[]array=new int[5]
创建数组时,计算机会在内存中为该数组中包含的数据保留五个连续的空间。但是,之后的内存空间可以立即用于存储其他信息。如果以后要调整数组的大小,则必须将其他信息移动到其他位置,以便使数组变大。这是我们不想处理的大量洗牌,因此计算机架构师不允许调整数组大小以使事情更简单。

数组在引擎盖下是一个连续的内存块。根据您将其初始化为什么,它可以相对较小,也可以相对较大

比方说,我有一个由十个元素组成的数组

int[] arr = new int[10];
JVM的底层实现现在必须要求操作系统为程序分配40个连续字节。操作系统要求,现在您有了40个字节,您可以使用熟悉的名称
arr

请注意,这个数组很可能在它的两侧共享空间-它附近有其他引用或信息位,它不能只是走到自己的第十一个位置并“声明”它

假设我们认为10太短了。我们需要把它放大十倍

int arr2 = new int[100];
现在,操作系统必须在内存中找到彼此相邻的400字节空间,考虑到对象的生命周期、垃圾收集的运行时间等等,这些空间可能很小,也可能不小

调整数组大小并不是简单地在几个内存位置上移动引用,而是查找新的连续内存块来存储数据


您提到了
ArrayList
——奇怪的是,它背后有一个数组,“自动”调整大小。嗯,调整大小的操作有一个陷阱-它很昂贵。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
ensureCapacityInternal
做了一些有趣的事情…最终调用
ensureExplicitCapacity
…最终调用
grow

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}
private void grow(int minCapacity){
//有溢出意识的代码
int oldCapacity=elementData.length;
int newCapacity=oldCapacity+(oldCapacity>>1);
if(新容量-最小容量<0)
新容量=最小容量;
if(新容量-最大阵列大小>0)
新容量=大容量(最小容量);
//minCapacity通常接近大小,因此这是一个胜利:
elementData=Arrays.copyOf(elementData,newCapacity);
}
本质上,每次需要调整大小时,它都会分配相当于原始备份阵列1.5倍的空间。如果
ArrayList
相当大,这会很快变得非常昂贵,系统必须找到越来越多的连续内存进行分配,这意味着JVM必须找到更多的连续空间,这意味着需要花费更多的时间进行垃圾收集,最终会降低性能


上述内容甚至不包括将数据复制回来。

Vague。没有指定语言。我认为没有指定语言。。因为这适用于C++和java。这个家伙有一个真正的问题,我看到人们在没有具体解释的情况下进行投票。我看不出有什么理由去否决这些问题。这个数组的默认大小是10。看,是的。。如果是动态创建的Arraylist(Arraylist、Vector等)。从旧数组复制值后,将删除旧数组并创建新数组。新的数组不必与旧的数组位于相同的位置/内存位置。“上面的内容甚至不包括将数据复制回来。”-对于java,我们只保留“引用”,从这个意义上讲,它更便宜。您对arraylist的工作原理非常了解,有一个替代调用linkedlist,但每个引用要多花2美元。。互让也是如此。。最好的方法是使用所需的初始大小声明arraylist,这样它就不会重新生成自身。在某些面向对象的环境中,每个对象引用都是一个表的索引,该表包含对象的实际地址。在这样的环境中,如果可以确定当时没有人在使用对象,那么允许对象的大小更改就不会是问题。问题在于,要使这些系统在多线程环境中安全,就必须锁定对对象的所有访问,而数组则提供了某些线程安全保证,即使没有锁定。