23

簡単な質問があります。私はJavaに整数配列を持っていますが、その長さはクラス全体で変化する必要があります。具体的には、状況によっては1つずつ増やす必要があります。こんな感じでやってみました。

        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()方法を使用することです。
  • ArrayList可変サイズのコレクションが必要な場合は、配列の代わりに使用する方がよいでしょう。

そうは言っても、コードの外部で作成された配列のサイズを変更する以外に選択肢がない場合があります。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";
    }
}

このメソッドでは、サイズ1mainの配列を作成します。このメソッドでは、配列の境界外に4つの追加の値が割り当てられます。このコードをそのまま実行すると、明らかにエラーが発生します。Stringfun

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は2つのコマンドで構成されます。

  • iconst_1int、値1の定数をスタック( )にプッシュします0x04
  • anewarray、スタックの値をポップし、同じサイズの参照配列30xbdを作成します( )。上記のコードは、クラス内のコマンドの組み合わせを探し、見つかった場合は、コマンドをコマンド( )Mainに置き換えて、配列の次元を5に効果的に変更します。4const_1const_50x08

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プリミティブ配列の場合、対応するバイトコード操作は代わりにnewarray0xbc)になります。
4すでに述べたように、これは概念実証にすぎません(そして非常にハッキーなものです)。バイトをランダムに置き換える代わりに、より堅牢な実装では、 ASMのようなバイトコード操作ライブラリを使用できます。またはコマンドの前にコマンドを挿入し、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を使用できます。実際に何が起こるかというと、VMはArrayListによって公開される配列の「サイズを調整」*します。

も参照してください

*バックコピーアレイを使用

于 2012-04-21T01:30:17.137 に答える
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 に答える
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 に答える
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 に答える