23

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

        sbgHeadX = new int[ numberOfSBG ];

我会在需要时增加整数变量 numberOfSBG,但我认为这行不通。还有其他方法吗?

4

10 回答 10

35

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

Arrays.copyOf() 

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

于 2012-04-21T01:33:04.383 回答
25

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));

或者,您可以使用动态数据结构,如列表。

于 2012-04-21T01:34:32.117 回答
16

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

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

来源

于 2012-04-21T01:30:36.873 回答
3

第一件事:

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

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

概念验证

下面是一个小型的概念验证项目,它使用 Java工具来动态更改数组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方法中,我们创建了一个String大小为 1 的数组。在该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,它将int值为 1 的常量压入堆栈 ( 0x04)。
  • anewarray,它弹出堆栈的值并创建一个相同大小的引用数组3 ( 0xbd)。上面的代码在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这种情况出现在这里这里的问题,后者促使我写下这个答案。
2从技术上讲,示例项目不会调整数组的大小。它只是使用与代码中指定的大小不同的大小创建它。实际上,在保持其引用并复制其元素的同时调整现有数组的大小会稍微复杂一些。
3对于原始数组,相应的字节码操作将改为newarray( )。4如前所述,这只是一个概念证明(而且是一个非常老套的证明)。代替随机替换字节,更健壮的实现可以使用像ASM这样的字节码操作库0xbc
在任何或命令之前插入一个pop命令,然后是一个命令。可以在对此答案的评论中找到有关该解决方案的更多提示。5在现实世界的场景中,代理代码显然会在一个单独的项目中。sipushnewarrayanewarray

于 2018-12-19T09:30:39.607 回答
2

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

这个例子可以帮助你。该示例的输出非常简单。

输出:
2 5 1 23 14
新长度:20
索引 5:29 处的元素
列表大小:6
删除索引 2 处的元素:1
2 5 23 14 29
于 2016-09-13T07:22:39.257 回答
1

根据定义,数组是固定大小的。您可以使用 Arraylist 来代替,即“动态大小”数组。实际上发生的情况是虚拟机“调整大小”* ArrayList 公开的数组。

也可以看看

*使用备份数组

于 2012-04-21T01:30:17.137 回答
1

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

static int[] arrayLengthChange(int[] arr, int newLength) {
    int[] arrNew = new int[newLength];
    System.arraycopy(arr, 0, arrNew, 0, arr.length);
    return arrNew;
}
于 2019-01-16T12:35:56.823 回答
1
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;
于 2016-09-13T07:13:48.507 回答
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);
}
于 2021-01-18T12:54:18.877 回答
0

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

没有本地方法可以做到这一点,但你可以使用类似这样的东西:

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

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

于 2021-04-16T11:56:05.640 回答