如何增加数组的长度

时间:2012-04-21 01:28:24

标签: java arrays

我有一个简单的问题。我在java中有一个整数数组,需要它的长度在整个类中变化。具体来说,我需要在某些情况下增加1。我试过这样的。

        sbgHeadX = new int[ numberOfSBG ];

我会在需要时增加整数变量numberOfSBG,但我认为这不起作用。还有其他办法吗?

10 个答案:

答案 0 :(得分:24)

如果您不想或不能使用ArrayList,那么有一个实用方法:

Arrays.copyOf() 

允许您指定新大小,同时保留元素。

答案 1 :(得分:23)

Java中的数组具有固定大小,在声明时指定。要增加数组的大小,您必须创建一个更大的新数组,并将所有旧值复制到新数组中。

例如:

char[] copyFrom  = { 'a', 'b', 'c', 'd', 'e' };
char[] copyTo    = new char[7];

System.out.println(Arrays.toString(copyFrom));
System.arraycopy(copyFrom, 0, copyTo, 0, copyFrom.length);
System.out.println(Arrays.toString(copyTo));

或者,您可以使用像List这样的动态数据结构。

答案 2 :(得分:14)

我建议您使用ArrayList,因为您不必再​​担心长度了。创建后,您无法修改数组大小:

  

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

Source

答案 3 :(得分:1)

根据定义,数组是固定大小的。您可以使用Arraylist,即“动态大小”数组。实际上会发生什么是VM“调整ArrayList公开的数组的大小”*。

See also

*使用反向复制数组

答案 4 :(得分:1)

您可以使用ArrayList。数组具有固定数量的大小。

Example可以为您提供帮助。输出的例子非常简单。

Output:
2 5 1 23 14 
New length: 20
Element at Index 5:29
List size: 6
Removing element at index 2: 1
2 5 23 14 29

答案 5 :(得分:1)

第一件事:

  • 在Java中,一旦创建数组,其长度就是固定的。数组无法调整大小。
  • 您可以将数组的元素复制到具有不同大小的新数组。最简单的方法是使用Arrays.copyOf()方法之一。
  • 如果您需要一个可变大小的集合,最好使用ArrayList而不是数组。

话虽如此,在某些情况下,除了更改在代码之外的某个地方创建的数组的大小,您别无选择。 1 唯一的方法是操作生成数组的代码的生成字节码。

概念证明

以下是一个小型的概念验证项目,该项目使用Java instrumentation动态更改数组 2 的大小。该示例项目是一个具有以下结构的Maven项目:

.
├─ pom.xml
└─ src
   └─ main
      └─ java
         └─ com
            └─ stackoverflow
               └─ agent
                  ├─ Agent.java
                  └─ test
                     └─ Main.java

Main.java

此文件包含我们将要操作其字节码的目标类:

package com.stackoverflow.agent.test;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        String[] array = {"Zero"};

        fun(array);

        System.out.println(Arrays.toString(array));
    }

    public static void fun(String[] array) {
        array[1] = "One";
        array[2] = "Two";
        array[3] = "Three";
        array[4] = "Four";
    }
}

main方法中,我们创建一个大小为1的String数组。在fun方法中,在数组范围之外分配了4个其他值。按原样运行此代码显然会导致错误。

Agent.java

此文件包含将执行字节码操作的类:

package com.stackoverflow.agent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class Agent {
    public static void premain(String args, Instrumentation instrumentation) {
        instrumentation.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader l, String name, Class<?> c,
                    ProtectionDomain d, byte[] b) {

                if (name.equals("com/stackoverflow/agent/test/Main")) {
                    byte iconst1 = (byte) 0x04;
                    byte iconst5 = (byte) 0x08;
                    byte anewarray = (byte) 0xbd;

                    for (int i = 0; i <= b.length - 1; i++) {
                        if (b[i] == iconst1 && b[i + 1] == anewarray) {
                            b[i] = iconst5;
                        }
                    }

                    return b;
                }

                return null;
            }
        });
    }
}

在字节码级别,String类中Main数组的创建包含两个命令:

  • iconst_1,它将值为1的int常量推入堆栈(0x04)。
  • anewarray,这会弹出堆栈的值并创建大小相同(0xbd)的引用数组 3 。 上面的代码在Main类中查找命令的组合,如果找到,将const_1命令替换为const_5命令(0x08),从而有效地更改尺寸数组的大小为5. 4

pom.xml

maven POM文件用于构建应用程序JAR并配置主类和Java代理类。 5

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.stackoverflow</groupId>
  <artifactId>agent</artifactId>
  <version>1.0-SNAPSHOT</version>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.1</version>
        <configuration>
          <archive>
            <manifestEntries>
              <Main-Class>com.stackoverflow.agent.test.Main</Main-Class>
              <Premain-Class>com.stackoverflow.agent.Agent</Premain-Class>
              <Agent-Class>com.stackoverflow.agent.Agent</Agent-Class>
              <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

构建并执行

可以使用标准mvn clean package命令来构建示例项目。

不参考代理代码执行将产生预期的错误:

$> java -jar target/agent.jar 
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
        at com.stackoverflow.agent.test.Main.fun(Main.java:15)
        at com.stackoverflow.agent.test.Main.main(Main.java:9)

使用代理代码执行时会产生:

$> java -javaagent:target/agent.jar -jar target/agent.jar
[Zero, One, Two, Three, Four]

这表明使用字节码操作成功更改了数组的大小。


1 这种情况出现在问题herehere中,其中后者促使我写下了这个答案。
2 从技术上讲,示例项目不会调整数组的大小。它创建的大小与代码中指定的大小不同。实际上,在调整现有数组大小的同时保留其引用并复制其元素会稍微复杂一些。
3 对于原始数组,相应的字节码运算应为newarray0xbc)。
4 如前所述,这只是概念上的证明(也是一个很拙劣的解释)。代替随机替换字节,更健壮的实现可以使用ASM之类的字节码操作库在任何pop或{{之前,先插入sipush命令,然后插入newarray命令3}}命令。可以在anewarray的注释中找到有关该解决方案的更多提示。
5 在实际情况下,代理代码显然将在单独的项目中。

答案 6 :(得分:0)

Item[] newItemList = new  Item[itemList.length+1];
    //for loop to go thorough the list one by one
    for(int i=0; i< itemList.length;i++){
        //value is stored here in the new list from the old one
        newItemList[i]=itemList[i];
    }
    //all the values of the itemLists are stored in a bigger array named newItemList
    itemList=newItemList;

答案 7 :(得分:0)

数组长度更改方法示例(使用旧数据处理):

static int[] arrayLengthChange(int[] arr, int newLength) {
    int[] arrNew = new int[newLength];
    System.arraycopy(arr, 0, arrNew, 0, arr.length);
    return arrNew;
}

答案 8 :(得分:0)

如果数组未在堆内存中声明,则不能增加数组的长度(请参阅下面的代码,用户询问第一个数组输入,然后询问您要增加多少数组并复制以前的数组元素):

#include<stdio.h>
#include<stdlib.h>

int * increasesize(int * p,int * q,int x)
{
    int i;
    for(i=0;i<x;i++)
    {
         q[i]=p[i];
    }
    free(p);
    p=q;
    return p;
}
void display(int * q,int x)
{
    int i;
    for(i=0;i<x;i++)
    {
        printf("%d \n",q[i]);
        
    }
}

int main()
{
    int x,i;
    printf("enter no of element to create array");
    scanf("%d",&x);
    int * p=(int *)malloc(x*sizeof(int));
    printf("\n enter number in the array\n");
    for(i=0;i<x;i++)
    {
        scanf("%d",&p[i]);
    }
    int y;
    printf("\nenter the new size to create new size of array");
    scanf("%d",&y);
    int * q=(int *)malloc(y*sizeof(int));
    display(increasesize(p,q,x),y);
    free(q);
}

答案 9 :(得分:0)

回答您的问题而不说“使用 ArrayList”之类的话,这可能并不总是一种选择,特别是当您想要最佳性能时:

没有本地方法可以做到这一点,但您可以使用以下内容:

int[] newArray = new int[oldArray.length + 1];
System.arrayCopy(oldArray, 0, newArray, 0, oldArray.length);
oldArray = newArray;

就是这样,最后一个位置可以免费使用。请注意,您可以将“1”更改为您喜欢的任何数字。如果你重复使用它,你也可以用这段代码制作一个方法。