web-dev-qa-db-fra.com

Comment augmenter la longueur d'un tableau

J'ai une petite question. J'ai un tableau entier en Java qui a besoin de sa longueur pour varier dans la classe. Plus précisément, il me faut une augmentation d'un dans certaines situations. J'ai essayé comme ça.

        sbgHeadX = new int[ numberOfSBG ];

J'augmenterais la variable entière numberOfSBG lorsque j'en aurais besoin, mais je ne pense pas que cela fonctionne. Y-a t'il une autre possibilité?

18
kullalok

Je suggérerais que vous utilisiez un ArrayList car vous n’aurez plus à vous soucier de la longueur. Une fois créé, vous ne pouvez pas modifier la taille d'un tableau:

Un tableau est un objet conteneur qui contient un nombre fixe de valeurs d'un seul type. La longueur d'un tableau est établie lors de sa création. Après création, sa longueur est fixée.

( La source )

13
talnicolas

Si vous ne voulez pas ou ne pouvez pas utiliser ArrayList, il existe une méthode utilitaire:

Arrays.copyOf() 

cela vous permettra de spécifier une nouvelle taille tout en préservant les éléments.

23
Jakub Zaverka

Les tableaux en Java ont une taille fixe, spécifiée lors de leur déclaration. Pour augmenter la taille du tableau, vous devez créer un nouveau tableau avec une taille plus grande et copier toutes les anciennes valeurs dans le nouveau tableau.

ex:

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

Vous pouvez également utiliser une structure de données dynamique telle qu'une liste.

23
Hunter McMillen

Par définition, les tableaux ont une taille fixe. Vous pouvez utiliser à la place un Arraylist, un tableau de "taille dynamique". En réalité, la VM "ajuste la taille" * du tableau exposé par ArrayList.

Voir également

* en utilisant des tableaux de back-copy

1
Erre Efe

Vous pouvez utiliser ArrayList. Le tableau a le nombre fixe de taille. 

Cet Exemple ici peut vous aider. L'exemple est assez facile avec sa sortie. 

 Sortie: 
 2 5 1 23 14 
Nouvelle longueur: 20 
Élément à l'Index 5:29 
Taille de la liste: 6 
Enlèvement d’élément à l’indice 2: 1 
2 5 23 14 29
1
Dalpat Singh

Exemple de méthode de changement de longueur de tableau (avec l'ancien traitement des données)

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

Premières choses d'abord:

  • En Java, une fois qu'un tableau est créé, sa longueur est fixe. Les tableaux ne peuvent pas être redimensionnés. 
  • Vous pouvez copier les éléments d'un tableau dans un nouveau tableau de taille différente. Pour ce faire, la méthode la plus simple consiste à utiliser l’une des méthodes Arrays.copyOf() .
  • Si vous avez besoin d'une collection de taille variable, il vaut probablement mieux utiliser un ArrayList au lieu d'un tableau.

Cela étant dit, il peut arriver que vous n'ayez d'autre choix que de changer la taille d'un tableau créé quelque part en dehors de votre code.1 La seule façon de faire est de manipuler le bytecode généré du code qui crée le tableau.

Preuve de concept

Vous trouverez ci-dessous un petit projet de démonstration de concept utilisant Java instrumentation pour modifier de manière dynamique la taille d'un tableau.2. Le projet exemple est un projet maven ayant la structure suivante:

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

Main.Java

Ce fichier contient la classe cible dont nous allons manipuler le bytecode:

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";
    }
}

Dans la méthode main, nous créons un tableau String de taille 1. Dans la méthode fun, 4 valeurs supplémentaires sont attribuées en dehors des limites du tableau. L'exécution de ce code en l'état entraînera évidemment une erreur.

Agent.Java

Ce fichier contient la classe qui effectuera la manipulation du bytecode:

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

Au niveau du bytecode, la création du tableau String dans la classe Main consiste en deux commandes:

  • iconst_1 , qui insère une constante int de valeur 1 dans la pile (0x04).
  • anewarray , qui affiche la valeur de la pile et crée un tableau de référence3 de même taille (0xbd) . Le code ci-dessus recherche cette combinaison de commandes dans la classe Main et, le cas échéant, remplace la commande const_1 par une commande const_5 (0x08), modifiant ainsi les dimensions du tableau en 5 .4

pom.xml

Le fichier POM maven est utilisé pour créer le fichier JAR de l’application et pour configurer la classe principale et la classe de l’agent 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>

Construire et exécuter

L'exemple de projet peut être construit à l'aide de la commande standard mvn clean package.

L'exécution sans faire référence au code de l'agent produira l'erreur attendue:

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

Lors de l'exécution avec le code de l'agent, vous obtiendrez:

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

Cela démontre que la taille du tableau a été modifiée avec succès à l'aide de la manipulation de code intermédiaire.


1 De telles situations sont apparues dans les questions ici et ici , lesquelles m'ont incité à écrire cette réponse.
2 Techniquement, l'exemple de projet ne redimensionne pas le tableau. Il le crée simplement avec une taille différente de celle spécifiée dans le code. Redimensionner un tableau existant tout en conservant sa référence et en copiant ses éléments serait un peu plus compliqué.
3 Pour un tableau primitif, l'opération de bytecode correspondante serait newarray (0xbc) à la place.
4 Comme indiqué, ceci est juste une preuve de concept (et une très hacky à cela). Au lieu de remplacer aléatoirement des octets, une implémentation plus robuste pourrait utiliser une bibliothèque de manipulation de code unique comme ASM pour insérer une commande pop suivie d'une sipush avant commande newarray ou anewarray . Quelques commentaires supplémentaires sur cette solution peuvent être trouvés dans les commentaires de cette réponse .
5 Dans un scénario réel, le code de l'agent serait évidemment dans un projet séparé.

0
Robby Cornelissen
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;
0
karanbir singh