Как увеличить значение класса Integer ссылки в Java из другого метода - PullRequest
26 голосов
/ 05 февраля 2010
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...
    }
}

Результат для всех них равен n = 0. Целое число n является объектом и поэтому передается по ссылке, так почему же приращение не отражается обратно в методе вызова (main)? Я ожидал, что выходной сигнал будет n = 0 n = 1 n = 2 и т. Д.

UPDATE: Обратите внимание, я обновил пример кода выше. Если я правильно понимаю, Джон Скит ответил на вопрос, почему myInt будет увеличиваться, а почему n - нет. Это потому, что n получает новую ссылку, назначенную в методе Increment. Но myInt НЕ присваивается новая ссылка, так как он вызывает функцию-член.

Звучит так, будто я правильно понимаю, лол?

Ответы [ 10 ]

37 голосов
/ 05 февраля 2010

Нет, объекты не передаются по ссылке. Ссылки передаются по значению - есть большая разница. Integer является неизменным типом, поэтому вы не можете изменить значение в методе.

Ваше n++; утверждение эффективно

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

Итак, это назначает другое значение переменной n в Increment - но поскольку Java только имеет передачу по значению, это не влияет на значение n вызывающий метод.

РЕДАКТИРОВАТЬ: Чтобы ответить на ваше обновление: это верно. Предположительно ваш тип "MyIntegerObj" является изменяемым и меняет свое внутреннее состояние при вызове plusplus(). Да, и не беспокойтесь о том, как реализовать оператор - Java не поддерживает определяемые пользователем операторы.

24 голосов
/ 05 февраля 2010

Вы можете использовать AtomicInteger из java.util.concurrent.atomic. У него есть метод incrementAndGet, подходящий для вашей витрины.

6 голосов
/ 05 февраля 2010

Вы ищете что-то похожее на ссылку C ++ или на параметр C # out. Java (и многие другие языки) не поддерживают это.

Этот тип поведения обычно достигается путем изменения метода с void на (в данном случае) int: public static int increment(int n) { return ++n; }

Если метод уже возвращает что-то, вы можете создать новый класс, который имеет два поля (может быть даже публичным): исходное возвращаемое значение и новое значение n.

Кроме того, вы также можете заключить целое число в общий класс Cell. Вам нужно написать этот класс Cell только один раз:

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

Затем вы можете использовать его во всех ситуациях, когда вы хотите, чтобы метод изменил примитив:

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
3 голосов
/ 05 февраля 2010

Примечание: по моему скромному мнению, написание n ++ для объекта Integer крайне вводит в заблуждение. Это основывается на функции Java, называемой «autoboxing», где она автоматически и без предупреждения преобразует примитивы в соответствующие им объекты бокса - например, int в Integer или boolean в Boolean. Честно говоря, я думаю, что это плохая особенность. Да, иногда это делает вашу жизнь проще, автоматически делая удобное преобразование для вас, но оно также может выполнять преобразования, которые вы не планировали и не понимаете, происходят с непреднамеренными побочными эффектами.

В любом случае, есть два способа выполнить то, что вы, очевидно, пытаетесь сделать:

One: функция приращения возвращает новое целое число с обновленным значением. Нравится:

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

затем назовите его с:

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

1011 * Etc. *

Два: Создайте свой собственный класс, который напоминает Integer, но который является изменяемым. Как:

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

Конечно, большая выгода заключается в том, что вам в значительной степени приходится заново изобретать класс Integer.

3 голосов
/ 05 февраля 2010

Как отметил Джон Скит, все методы в Java передаются по значению, а не по ссылке. Поскольку ссылочные типы передаются по значению, то, что у вас есть внутри тела функции, является копией ссылки - и эта копия, и исходная ссылка указывают на одно и то же значение.

Однако, если вы переназначите копию внутри тела функции, это не повлияет на остальную часть вашей программы, так как эта копия выйдет из области видимости при выходе из функции.

Но учтите, что вам на самом деле не нужен проход по ссылке, чтобы делать то, что вы хотите сделать. Например, вам не нужен метод для увеличения Integer - вы можете просто увеличить его в той точке кода, где его нужно увеличивать.

Для более сложных типов, таких как установка какого-либо свойства для объекта, объект, с которым вы работаете, вероятно, изменчив; в этом случае копия ссылки работает просто отлично, поскольку автоматическая разыменование приведет вас к исходному объекту, чей установщик вы вызываете.

2 голосов
/ 25 марта 2011

Как упомянуто DerMike , вы можете достичь этого следующим образом:

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 голосов
/ 05 февраля 2010

Вы не можете. Java строго передается по значению.

См. http://javadude.com/articles/passbyvalue.htm

Вы можете заключить целое число в объект (или массив), передать его и обновить, вернуть значение или сделать целое число переменной класса / экземпляра.

Что лучше, зависит от ситуации.

1 голос
/ 10 апреля 2014

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

Вы можете сделать это поточно-ориентированным, используя этот класс java.util.concurrent.

1 голос
/ 05 февраля 2010

Integer является объектом значения , что означает, что значение не может быть изменено.

Обратите внимание, что n++ является эквивалентом n = n + 1. Вы просто меняете значение, на которое указывает локальная переменная n, а не значение n.

0 голосов
/ 17 ноября 2018
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]);    
    }
}

выход:

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
...