Как передать примитивный тип данных по ссылке? - PullRequest
43 голосов
/ 01 декабря 2010

Как я могу передать примитивный тип по ссылке в Java? Например, как мне сделать int переданным методу, который можно модифицировать?

Ответы [ 8 ]

73 голосов
/ 01 декабря 2010

Нет способа передать примитив напрямую по ссылке в Java.

Обходной путь - вместо этого передать ссылку на экземпляр класса-оболочки, который затем содержит примитив в качестве поля-члена.Такой класс-обёртка может быть чрезвычайно простым для написания для себя:

public class IntRef { public int value; }

Но как насчет некоторых предварительно созданных классов-обёрток, чтобы нам не приходилось писать свои собственные?ОК:

Классы Apache commons-lang Mutable *:
Преимущества : Хорошая производительность для однопоточного использования.Полнота.
Недостатки : Внедряется зависимость от сторонней библиотеки.Нет встроенного контроля параллелизма.
Представительные классы : MutableBoolean , MutableByte , MutableDouble , MutableFloat , MutableInt , MutableLong , MutableObject , MutableShort .

java.util.concurrent.atomic Атомная* классы:
Преимущества : часть стандартного API Java (1.5+).Встроенные средства управления параллелизмом.
Недостатки : Небольшое снижение производительности при использовании в однопоточном режиме.Отсутствует прямая поддержка для некоторых типов данных, например, нет AtomicShort.
Представительные классы : AtomicBoolean , AtomicInteger , AtomicLong и AtomicReference .
Примечание . Как показывает пользователь ColinD в своем ответе , AtomicReference можно использовать для аппроксимации некоторых отсутствующих классов, например, AtomicShort.

Длина1 массив примитивов
Ответ OscarRyz демонстрирует использование массива длины 1 для "обертывания" примитивного значения.
Преимущества : Быстрая запись.Производительный.Нет необходимости в сторонней библиотеке.
Недостатки : Немного грязно.Нет встроенного контроля параллелизма.В результате получается код, который не (явно) самодокументирован: есть ли массив в сигнатуре метода, чтобы я мог передать несколько значений?Или это здесь в качестве основы для эмуляции передачи по ссылке?

Также см.
Ответы на вопрос StackOverflow " Изменяемое логическое поле в Java ".

Мое мнение
В Java вы должны стараться использовать вышеупомянутые подходы экономно или не использовать их вообще.В C обычно используется возвращаемое значение функции для передачи кода состояния (SUCCESS / FAILURE), в то время как фактический выход функции передается через один или несколько выходных параметров.В Java лучше использовать Исключения вместо кодов возврата.Это освобождает возвращаемые значения метода, которые будут использоваться для переноса фактического вывода метода - шаблон проектирования, который большинство Java-программистов считают более естественным, чем выходные параметры.

13 голосов
/ 01 декабря 2010

Передайте AtomicInteger, AtomicBoolean и т. Д. Вместо этого.Не существует одного для каждого примитивного типа, но вы также можете использовать, скажем, AtomicReference<Short>, если это необходимо.

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

13 голосов
/ 01 декабря 2010

Ничто в Java не передается по ссылке. Это все передается по значению.

Редактировать: И примитивы, и типы объектов передаются по значению. Вы никогда не сможете изменить переданное значение / ссылку и ожидать, что исходное значение / ссылка изменится. Пример:

String a;
int b;

doSomething(a, b);

...

public void doSomething(String myA, int myB) {
   // whatever I do to "myA" and "myB" here will never ever ever change
   // the "a" and "b"
}

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

С держателем:

private class MyStringHolder {
  String a;
  MyStringHolder(String a) {
    this.a = a;
  }
}

MyStringHolder holdA = new MyStringHolder("something");

public void doSomething(MyStringHolder holder) {
   // alter holder.a here and it changes.
}

С возвращаемым значением

int b = 42;
b = doSomething(b);

public int doSomething(int b) {
  return b + 1;
}
10 голосов
/ 01 декабря 2010

Это невозможно в Java, в качестве альтернативы вы можете заключить его в массив из одного элемента.

void demo() { 
    int [] a = { 0 };
    increment ( a ) 
}
void increment( int [] v ) { 
     v[0]++;
}

Но всегда есть лучшие варианты.

3 голосов
/ 01 декабря 2010

Вы не можете.Но вы можете вернуть целое число, которое является измененным значением

int i = 0;
i = doSomething(i);

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

2 голосов
/ 01 декабря 2010

Передайте объект, который имеет это значение, как поле.

1 голос
/ 01 декабря 2010

Это невозможно в Java

0 голосов
/ 01 декабря 2010

Один из вариантов - использовать такие классы, как java.lang.Integer, тогда вы вообще не будете передавать примитив.

С другой стороны, вы можете просто использовать код, подобный:

int a = 5;
a = func(a);

и func возвращает измененное значение.

...