Comment incrémenter une valeur de référence entière de classe 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. Entier n est un objet et donc passé par référence, alors pourquoi l'incrément n'est-il pas reflété dans la méthode caller (main)? I résultats escomptés: n=0 n=1 n = 2 etc...

mise à jour: 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 obtient une nouvelle référence assignée dans la méthode Increment. Mais myInt n'obtient pas une nouvelle référence puisqu'il appelle une fonction membre.

Est-ce que ça sonne comme si j'avais bien compris lol ?

26
demandé sur cchampion 2010-02-05 20:10:27

9 réponses

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, donc vous ne pouvez pas changer la valeur dans la méthode.

n++; déclaration est effectivement

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

donc, qui assigne une valeur différente à la variable nIncrement - mais comme Java a une valeur de passage, qui n'affecte pas la valeur de n dans la méthode appelante.

Modifier: To répondez à votre mise à jour: c'est exact. Probablement votre type "MyIntegerObj" est mutable, et change son état interne quand vous appelez plusplus(). OH, et ne cherchez pas à savoir comment implémenter un opérateur - Java ne supporte pas les opérateurs définis par l'utilisateur.

37
répondu Jon Skeet 2013-01-24 12:46:48

vous pourriez utiliser un AtomicIntegerjava.util.concurrent.atomic. Il a une méthode incrementAndGet qui convient à votre vitrine.

23
répondu DerMike 2010-02-05 17:13:08

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

ce type de comportement est typiquement obtenu en changeant la méthode de void En (dans ce cas) int: public static int increment(int n) { return ++n; }

si la méthode retourne déjà quelque chose alors vous pouvez créer une nouvelle classe qui a deux champs (peut même être public): la valeur de retour originale et la nouvelle valeur de N.

Alternativement, vous pouvez envelopper également l'entier à l'intérieur d'une classe de cellule Générique. Vous n'avez besoin d'écrire cette classe de cellules qu'une seule 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 voulez une méthode pour changer 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
répondu Itay Maman 2010-02-05 17:18:10

Comme Jon Skeet mentionné, toutes les méthodes en Java sont passé par valeur et non par référence. Puisque les types de référence sont passés par valeur, ce que vous avez à l'intérieur du corps de la fonction est une copie de la référence - cette copie et la référence originale pointent toutes deux vers la même valeur.

cependant, si vous réassignez la copie à l'intérieur du corps de la fonction, cela n'aura aucun effet sur le reste de votre programme car cette copie disparaîtra de la portée lorsque la fonction sortira.

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

pour les types plus complexes, comme définir une propriété sur un objet, L'objet avec lequel vous travaillez est probablement mutable; dans ce cas, une copie de la référence fonctionne très bien, puisque la déréférence automatique vous mènera à l'objet original dont vous êtes le setter. appel.

3
répondu danben 2010-02-05 17:20:23

Side note: à mon humble avis, Écrire n++ sur un objet entier est extrêmement trompeur. Cela s'appuie sur une fonctionnalité de Java appelée "autoboxing" où il convertit les primitifs à leurs objets de boxe correspondants -- comme int À entier ou booléen à booléen -- automatiquement et sans avertissement. Franchement je pense que c'est une mauvaise fonctionnalité. Oui, parfois il rend votre vie plus simple en faisant automatiquement une conversion pratique pour vous, mais il peut également faire des conversions que vous n'avez pas l'intention et ne pas réaliser se produisent, avec des effets secondaires involontaires.

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

One: demander à la fonction increment de retourner un nouvel entier avec la valeur mise à jour. Comme:

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

puis l'appeler 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 la grosse prise de ce que vous il faut à peu près réinventer la classe entière.

3
répondu Jay 2010-02-05 18:22:07

Vous ne pouvez pas. Java est strictement passé par valeur.

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

vos choix sont d'envelopper le nombre entier dans un objet (ou un tableau), passer dans et mettre à jour, retourner une valeur, ou faire le nombre entier une classe/instance variable.

ce Qui est mieux dépend de la situation.

2
répondu Joe 2010-02-05 17:14:41

DerMike mentionné, vous pouvez le faire 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
répondu JareQ 2011-03-25 11:54:23

Integer est un valeur de l'objet ce qui signifie que la valeur ne peut pas changer.

Notez que n++ est équivalent à n = n + 1. Vous changez simplement la valeur mentionnée par la variable locale n, pas la valeur de n lui-même.

1
répondu Kevin 2010-02-05 17:13:53

Voir AtomicInteger: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

vous pouvez le faire thread-safe en utilisant ce java.util.concurrente de classe.

1
répondu cjaniake 2014-04-09 21:01:05