Объект по ссылке против ссылки по значению - PullRequest
8 голосов
/ 27 февраля 2012

Я прочитал этот комментарий здесь: Передача строки по ссылке в Java?

Да, это неправильное представление.Это огромное распространенное заблуждение.Это приводит к вопросу об интервью, который я ненавижу: («как Java передает аргументы»).Я ненавижу это, потому что примерно половина интервьюеров действительно, кажется, хотят неправильного ответа («примитивы по значению, объекты по ссылке»).Правильный ответ длится дольше и, кажется, смущает некоторых из них.И они не будут убеждены: я клянусь, я завалил технический экран, потому что проверщик типа CSMajor услышал неправильное представление в колледже и полагал, что это Евангелие.Фэ.- CPerkins 13 августа 2009 г. в 14: 34

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

"В примитивах Javaпередаются по значению, а объекты передаются по ссылке. "

и:

" В Java ничего не передается по ссылке, а ссылки передаются по значению. "?

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

Ответы [ 4 ]

12 голосов
/ 27 февраля 2012

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

Существует очень простой тест, который вы можете сделать, чтобы выяснить, поддерживает ли язык передачу по ссылке. Спросите себя, можете ли вы написать функцию подкачки на языке, то есть что-то вроде

x == A, y == B

swap(x, y);

x == B, y == A

Как программист на Java, вы быстро понимаете, что не можете реализовать это в Java, поэтому вы (правильно) сделаете вывод, что Java не имеет передачу по ссылке.

Возвращаясь к вашим предложениям:

  • В Java примитивы передаются по значению, а объекты передаются по ссылке.

Это false . Я бы сказал, что вы можете передавать только то, что содержится в переменной, и, как я уже говорил выше, переменная не может содержать объект, поэтому вы не можете передавать объект вообще в Java.

  • В Java ничего не передается по ссылке, а ссылки передаются по значению.

Это true .

7 голосов
/ 27 февраля 2012

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

    int i    = 5;
    String s = "test";

где-то в памяти есть запись для i, которая выглядит следующим образом:

  i
-----
| 5 |
-----

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

                            ----------- 
 s                 |------->|  "test" |
-----              |        |---------|
| --|--------------|        |         |
-----                       |         |
                            |         |
                            |---------|

Таким образом, значение s является ссылкой на тот объект String, который находится в куче, поэтому, если s было передано методу:

printString(s);

public void printString(String arg)
{
   System.out.println(arg);
}

значение, которое фактически копируется в параметр arg, является ссылкой на s в куче:

                            ----------- 
 s                 |------->|  "test" |<-----|
-----              |        |---------|      |
| --|--------------|        |         |      |
-----                       |         |      |
                            |         |      |
                            |---------|      |
 arg                                         |
-----                                        |
| --|----------------------------------------- 
-----

Надеюсь, это поможет.

6 голосов
/ 27 февраля 2012

Хороший вопрос. Рассмотрим следующий пример

void foo(Object obj) {
  obj = new Foo(); 
}
Object o = new Bar();
foo(o);
// is o Foo or Bar?
  • Если pass by-reference ссылка o могла бы измениться после вызова foo
  • Если pass by-reference-by-value, ссылка o остается неизменной после вызова foo
2 голосов
/ 27 февраля 2012

Оба утверждения являются взаимоисключающими, а первое утверждение является ложным.В Java все передается по значению, даже ссылки на объекты.Путаница проистекает из того факта, что когда объект передается по значению, то передается копия его ссылки, и если объект является изменяемым и модифицируется внутри метода, изменения будут видны изснаружи в том месте, где он был назван.

Позвольте мне объяснить пару примеров.В этом случае x - это тип примитива, переданный по значению:

void m(int x) {
    x = 10;
}
// in some other place, the above method gets called
x = 5;
m(x);
// in here, x's value is still 5

В этом случае x - это тип объекта, а копия его ссылки передается по значению:

void m(ArrayList<Integer> x) {
    x.add(10);
}
// in some other place, the above method gets called
ArrayList<Integer> x = new ArrayList<Integer>();
x.add(5);
m(x);
// in here, x contains [5, 10]
...