web-dev-qa-db-fra.com

Comment incrémenter une classe Integer référence une valeur en Java à partir d'une autre méthode

package myintergertest;

/**
 *
 * @author Engineering
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //this one does not increment 
        Integer n = new Integer(0);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);

        //this one will increment
        MyIntegerObj myInt = new MyIntegerObj(1);
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());

    }

    public static void Increment(Integer n) {
        //NO.  this doesn't work because a new reference is being assigned
        //and references are passed by value in Java
        n++;
    }

    public static void Increment(MyIntegerObj n) {
        //this works because we're still operating on the same object
        //no new reference was assigned to n here.
        n.plusplus();   //I didn't know how to implement a ++ operator...
    }
}

Le résultat pour tout cela est n = 0. L'entier n est un objet et est donc passé par référence. Pourquoi l'incrément n'est-il pas reflété dans la méthode de l'appelant (main)? Je m'attendais à ce que la sortie soit n = 0 n = 1 n = 2 etc ...

UPDATE: Notez que j'ai mis à jour l'exemple de code ci-dessus. Si je comprends bien, Jon Skeet a répondu à la question de savoir pourquoi myInt augmenterait et pourquoi n ne le ferait pas. C'est parce que n se voit attribuer une nouvelle référence dans la méthode Incrément. Mais myInt ne reçoit PAS de nouvelle référence car il appelle une fonction membre.

Est-ce que cela ressemble à ce que je comprends correctement lol?

26
cchampion

Non, les objets ne sont pas passés par référence. Les références sont passées par valeur - il y a une grande différence. Integer est un type immuable, vous ne pouvez donc pas modifier la valeur dans la méthode.

Votre déclaration n++; est effectivement

n = Integer.valueOf(n.intValue() + 1);

Donc, cela attribue une valeur différente à la variable n dans Increment - mais en tant que Java only a une valeur de passage, cela n'affecte pas la valeur de n dans la méthode d'appel.

EDIT: Pour répondre à votre mise à jour: c'est vrai. Vraisemblablement, votre type "MyIntegerObj" est modifiable et modifie son état interne lorsque vous appelez plusplus(). Oh, et ne cherchez plus comment implémenter un opérateur - Java ne prend pas en charge les opérateurs définis par l'utilisateur.

37
Jon Skeet

Vous pouvez utiliser une AtomicInteger de Java.util.concurrent.atomic. Il a une méthode 'incrementAndGet' qui convient à votre vitrine.

24
DerMike

Vous recherchez quelque chose de similaire à la référence de C++ ou au paramètre out de C #. Java (et beaucoup d'autres langages) ne le supporte pas.

Ce type de comportement est généralement obtenu en modifiant la méthode de void à (dans ce cas) int: public static int increment(int n) { return ++n; }

Si la méthode renvoie déjà quelque chose, vous pouvez créer une nouvelle classe comportant deux champs (pouvant même être publics): la valeur de retour d'origine et la nouvelle valeur de n.

Sinon, vous pouvez également envelopper l'entier dans une classe de cellule générique. Il vous suffit d'écrire cette classe de cellule une fois:

public class Cell<T> {
  public Cell(T t) { value = t; }
  public void set(T t) { value = t; }
  public T get() { return value; }
}

Vous pouvez ensuite l'utiliser dans toutes les situations où vous souhaitez utiliser une méthode pour modifier une primitive:

public static void increment(Cell<Integer> n) {
  n.set(n.get()++);
}

Cell<Integer> n = new Cell<Integer>(0);
increment(n);
increment(n);
increment(n);
System.out.println(n.get()); // Output: 3
6
Itay Maman

Note latérale: À mon humble avis, écrire n ++ sur un objet Integer est extrêmement trompeur. Cela repose sur une fonctionnalité de Java appelée "autoboxing" qui convertit les primitives en objets de boxe correspondants - comme int en Integer ou boolean en booléen - automatiquement et sans avertissement. Franchement, je pense que c'est une mauvaise fonctionnalité. Oui, cela vous simplifie parfois la vie en effectuant automatiquement une conversion pratique, mais vous pouvez également effectuer des conversions que vous n'aviez pas l'intention de réaliser et dont vous ne vous rendez pas compte, avec des effets secondaires non désirés.

Quoi qu'il en soit, il y a deux façons d'accomplir ce que vous essayez apparemment de faire:

One: Demander à la fonction d'incrémentation de renvoyer un nouvel entier avec la valeur mise à jour. Comme: 

   public Integer increment(Integer n)
    {
      Integer nPlus=Integer.valueOf(n.intValue()+1);
    }

puis appelez-le avec:

Integer n=Integer.valueOf(0);
n=increment(n); // now n==1
n=increment(n); // now n==2

Etc.

Deux: Créez votre propre classe qui ressemble à Integer mais qui est mutable. Comme:

class MutableInteger
{
  int value;
  public MutableInteger(int n)
  {
    value=n;
  }
  public void increment()
  {
    ++value;
  }
  ... whatever other functions you need ...
}

Bien sûr, le gros problème, c’est que vous devez pratiquement réinventer la classe Integer.

3
Jay

Comme Jon Skeet l'a mentionné, toutes les méthodes en Java sont passe-par-valeur, pas passe-par-référence. Les types de référence étant passés par valeur, le corps de la fonction contient une copie de la référence. Cette copie et la référence d'origine pointent toutes deux vers la même valeur.

Toutefois, si vous réaffectez la copie à l'intérieur du corps de la fonction, cela n'aura aucun effet sur le reste de votre programme, car cette copie ne sera plus à la portée de la tâche lorsque la fonction sera fermée.

Mais considérez que vous n'avez pas vraiment besoin de passer par référence pour faire ce que vous voulez faire. Par exemple, vous n'avez pas besoin d'une méthode pour incrémenter une Integer; vous pouvez simplement l'incrémenter au point de votre code où elle doit être incrémentée.

Pour les types plus complexes, comme la définition d'une propriété sur un objet, l'objet avec lequel vous travaillez est susceptible d'être muté; dans ce cas, une copie de la référence fonctionne parfaitement, car la déréférence automatique vous mènera à l'objet d'origine dont vous appelez le programmeur.

3
danben

Tu ne peux pas. Java est strictement pass-par-valeur.

Voir http://javadude.com/articles/passbyvalue.htm

Vous avez le choix entre envelopper le nombre entier dans un objet (ou un tableau), le transmettre et le mettre à jour, renvoyer une valeur ou transformer le nombre entier en une variable classe/instance.

Ce qui est mieux dépend de la situation.

2
Joe

En tant que DerMike mentionné, vous pouvez y parvenir comme suit:

public void doStuff() {
  AtomicInteger i = new AtomicInteger(0);
  increment(i);
  System.out.println(i);
 }

  public void increment(AtomicInteger i) {
    i.set(i.get() + 1);
 }
2
JareQ

Voir AtomicInteger: http://docs.Oracle.com/javase/7/docs/api/Java/util/concurrent/atomic/AtomicInteger.html

Vous pouvez le faire en thread-safe en utilisant cette classe Java.util.concurrent.

1
cjaniake

Integer est un objet value ce qui signifie que value ne peut pas changer.

Notez que n++ est l'équivalent de n = n + 1. Vous ne faites que modifier la valeur à laquelle la variable locale n fait référence, et non la valeur de n.

1
Kevin
public class passByReferenceExample {
    static void incrementIt(Long b[]){
        Long c = b[0];
        c=c+1;
        b[0]=c;

    }
    public static void main(String[] args) {
        Long a[]={1L};  

        System.out.println("Before calling IncrementIt() : " + a[0]);
        System.out.println();
        incrementIt(a);
        System.out.println("after first call to incrementIt() : " + a[0]);
        incrementIt(a);
        System.out.println("after second call to incrementIt(): "+ a[0]);
        incrementIt(a);
        System.out.println("after third call to incrementIt() : "+ a[0]);
        incrementIt(a);
        System.out.println("after fourth  call to incrementIt(): "+ a[0]);    
    }
}

sortie:

Before calling IncrementIt() : 1

after first call to incrementIt() : 2
after second call to incrementIt(): 3
after third call to incrementIt() : 4
after fourth  call to incrementIt(): 5
0
Suresh