66 votes

Comment changer la valeur d'un élément ArrayList en java

Veuillez m'aider avec le code ci-dessous, j'obtiens le même résultat même après avoir changé la valeur

import java.util.*;

class Test {
    public static void main(String[] args) {
        ArrayList a = new ArrayList();

       // ajouté 0-9 à ArrayList        
          for(int i=0;i<9;i++)
            a.add(new Integer(i));

        // initialiser l'itérateur
        Iterator i = a.iterator();

        // changer la valeur du premier élément dans la liste
        if(i.hasNext()) {
            Integer x = i.next();
            x = Integer.valueOf(9);
        }

        // réinitialiser l'itérateur et imprimer tous les éléments
        i = a.iterator();
        while(i.hasNext())
            System.out.print(i.next());
    }
}    

//Résultat : 012345678

La valeur 9 ne se met pas à jour.

87voto

Duncan Points 22780

La liste conserve une référence d'objet à la valeur d'origine stockée dans la liste. Donc lorsque vous exécutez cette ligne :

Integer x = i.next();

À la fois x et la liste stockent une référence au même objet. Cependant, lorsque vous exécutez :

x = Integer.valueOf(9);

rien n'a changé dans la liste, mais x stocke maintenant une référence à un objet différent. La liste n'a pas changé. Vous devez utiliser certaines des méthodes de manipulation de la liste, telles que

list.set(index, Integer.valueof(9))

Remarque : cela n'a absolument rien à voir avec l'immutabilité de Integer, comme le suggèrent d'autres. Il s'agit simplement du comportement de référence d'objet Java de base.


Voici un exemple complet, pour expliquer le point. Notez que cela utilise la classe ListIterator, qui prend en charge la suppression/le remplacement d'éléments en cours d'itération :

import java.util.*;

public class ListExample {

  public static void main(String[] args) {

    List fooList = new ArrayList();
    for (int i = 0; i < 9; i++)
      fooList.add(new Foo(i, i));

    // Itérateur standard suffisant pour modifier les éléments
    Iterator iterator = fooList.iterator();

    if (iterator.hasNext()) {
      Foo foo = iterator.next();
      foo.x = 99;
      foo.y = 42;
    }

    printList(fooList);    

    // Itérateur de liste nécessaire pour remplacer des éléments
    ListIterator listIterator = fooList.listIterator();

    if (listIterator.hasNext()) {
      // Besoin d'appeler next, avant set.
      listIterator.next();
      // Remplacer l'élément retourné par next()
      listIterator.set(new Foo(99,99));
    }

    printList(fooList);
  }

  private static void printList(List list) {
    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
      System.out.print(iterator.next());
    }
    System.out.println();
  }

  private static class Foo {
    int x;
    int y;

    Foo(int x, int y) {
      this.x = x;
      this.y = y;
    }

    @Override
    public String toString() {
      return String.format("[%d, %d]", x, y);
    }
  }
}

Cela affichera :

[99, 42][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]
[99, 99][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]

11voto

Joachim Isaksson Points 85969

Où vous dites que vous changez la valeur du premier élément;

x = Integer.valueOf(9);

Vous changez x pour pointer vers un nouvel Integer, mais ne l'utilisez plus jamais. Vous ne modifiez pas la collection de quelque manière que ce soit.

Comme vous travaillez avec ArrayList, vous pouvez utiliser ListIterator si vous voulez un itérateur qui vous permet de changer les éléments, voici l'extrait de votre code qui devrait être modifié;

//initialiser l'itérateur
ListIterator i = a.listIterator();

//changer la valeur du premier élément dans la liste
si(i.hasNext()) {
i.next();
i.set(Integer.valueOf(9)); // Changer l'élément sur lequel se trouve l'itérateur actuellement
}

// Nouvel itérateur, et afficher tous les éléments
Iterator iter = a.iterator();
while(iter.hasNext())
System.out.print(iter.next());

>> 912345678

Malheureusement, la même chose ne peut pas être étendue à d'autres collections comme Set. Des détails d'implémentation (comme par exemple un HashSet étant implémenté comme une table de hachage et le changement de l'objet pourrait changer la valeur de hachage et donc l'ordre d'itération) font de Set un type de structure de données "ajouter nouveau/supprimer seulement", et modifier le contenu en cours d'itération n'est pas sûr.

1voto

Bhesh Gurung Points 24875

Integer est immuable. Vous ne pouvez pas changer sa valeur.

Au lieu de cela, utilisez cette méthode E set(int index, E element). Remplacez l'ancien élément par le nouveau.

1voto

prateeksarda Points 141

Je suis d'accord avec Duncan ... J'ai essayé avec un objet mutable mais j'ai toujours le même problème... J'ai trouvé une solution simple à cela... utilisez ListIterator plutôt que Iterator et utilisez la méthode set de ListIterator

ListIterator i = a.listIterator();
//changement de la valeur du premier élément dans la List
Integer x =null;
        if(i.hasNext()) {
            x = i.next();
            x = Integer.valueOf(9);
        }
    //la méthode set définie l'élément récemment itéré dans ArrayList
    i.set(x);
        //réinitialise l'itérateur et imprime tous les éléments à nouveau
        i = a.listIterator();
        while(i.hasNext())
        System.out.print(i.next());

Mais cela me contraint à utiliser cela uniquement pour les ArrayList qui peuvent utiliser ListIterator... j'aurai le même problème avec n'importe quelle autre Collection

1voto

Je pense que le problème est que vous pensez que l'instruction ...

x = Integer.valueOf(9);

... provoque que la valeur '9' soit 'stockée' dans l'objet sur lequel x fait référence.

Mais ce n'est pas correct.

À la place, l'instruction provoque quelque chose de similaire à si vous appeliez

x = new Integer(9); 

Si vous regardez le code source Java, vous verrez ce qui se passe en détail.

Voici le code de la méthode "valueOf(int i)" dans la classe "Integer" :

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

et en outre, chaque fois que la classe IntegerCache est utilisée pour la première fois, le script suivant est invoqué :

static {
        // la valeur haute peut être configurée par une propriété
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // La taille maximale du tableau est Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

Vous voyez qu'un nouvel objet Integer est créé avec "new Integer(i)" dans la méthode valueOf ... ... ou une référence à un objet Integer qui est stocké dans IntegerCache est retournée.

Dans les deux cas, x fera référence à un nouvel objet.

Et c'est pourquoi la référence à l'objet dans votre liste est perdue lorsque vous appelez ...

x = Integer.valueOf(9);

Au lieu de faire cela, en combinaison avec un ListIterator, utilisez ...

i.set(Integer.valueOf(9));

... après avoir obtenu l'élément que vous souhaitez modifier avec ...

i.next();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X