Вопрос-ответ

Are arrays passed by value or passed by reference in Java? [duplicate]

Передаются ли массивы по значению или по ссылке в Java?

Массивы не являются примитивным типом в Java, но они также не являются объектами, поэтому передаются ли они по значению или по ссылке? Зависит ли это от того, что содержит массив, например ссылки или примитивный тип?

Переведено автоматически
Ответ 1

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

Когда вы передаете массив другому методу, фактически копируется ссылка на этот массив.


  • Любые изменения в содержимом массива через эту ссылку повлияют на исходный массив.

  • Но изменение ссылки так, чтобы она указывала на новый массив, не изменит существующую ссылку в исходном методе.

Смотрите этот пост: Является ли Java "передачей по ссылке" или "передачей по значению"?

Смотрите этот рабочий пример:

public static void changeContent(int[] arr) {

// If we change the content of arr.
arr[0] = 10; // Will change the content of array in main()
}

public static void changeRef(int[] arr) {
// If we change the reference
arr = new int[2]; // Will not change the array in main()
arr[0] = 15;
}

public static void main(String[] args) {
int [] arr = new int[2];
arr[0] = 4;
arr[1] = 5;

changeContent(arr);

System.out.println(arr[0]); // Will print 10..

changeRef(arr);

System.out.println(arr[0]); // Will still print 10..
// Change the reference doesn't reflect change here..
}
Ответ 2

Ваш вопрос основан на ложной предпосылке.


Массивы не являются примитивным типом в Java, но они также не являются объектами ... "


Фактически, все массивы в Java являются объектами1. Каждый тип массива Java имеет java.lang.Object в качестве своего супертипа и наследует реализацию всех методов в Object API.


... так они передаются по значению или по ссылке? Зависит ли это от того, что содержит массив, например ссылки или примитивный тип?


Короткие ответы: 1) передавать по значению и 2) это не имеет значения.

Более длинный ответ:

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

Это НЕ передача по ссылке. Реальная передача по ссылке предполагает передачу адреса переменной. С помощью реальной передачи по ссылке вызываемый метод может присваивать своей локальной переменной, и это приводит к обновлению переменной в вызывающем объекте.

Но не в Java. В Java вызываемый метод может обновлять содержимое массива, и он может обновлять свою копию ссылки на массив, но он не может обновлять переменную в вызывающем объекте, который содержит ссылку на массив вызывающего объекта. Следовательно ... то, что предоставляет Java, НЕ является передачей по ссылке.

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

Связанный с SO вопрос:

Историческая справка:

Фраза "передача по ссылке" изначально была "вызов по ссылке", и она использовалась, чтобы отличить семантику передачи аргументов FORTRAN (вызов по ссылке) от семантики ALGOL-60 (вызов по значению и вызов по имени).


  • В вызове по значению выражение аргумента вычисляется до значения, и это значение копируется в вызываемый метод.


  • В вызове по ссылке выражение аргумента частично вычисляется до "lvalue" (т. Е. Адреса переменной или элемента массива), который передается вызывающему методу. Затем вызывающий метод может напрямую считывать и обновлять переменную / элемент.


  • При вызове по имени фактическое выражение аргумента передается вызывающему методу (!!), который может вычислять его несколько раз (!!!). Это было сложно реализовать, и могло использоваться (злоупотреблять) для написания кода, который было очень сложно понять. Вызов по имени когда-либо использовался только в Algol-60 (к счастью!).


Обновить

На самом деле, вызов Algol-60 по имени аналогичен передаче лямбда-выражений в качестве параметров. Проблема заключается в том, что эти не совсем лямбда-выражения (их называли "thunks" на уровне реализации) могут косвенно изменять состояние переменных, которые находятся в области видимости вызывающей процедуры / функции. Это часть того, что сделало их такими трудными для понимания. (Например, смотрите страницу в Википедии об устройстве Дженсена.)


1. Ничто в связанных вопросах и ответах (Массивы в Java и то, как они хранятся в памяти) не указывает и не подразумевает, что массивы не являются объектами.

Ответ 3

Массивы на самом деле являются объектами, поэтому передается ссылка (сама ссылка передается по значению, вы еще не перепутали?). Краткий пример:

// assuming you allocated the list
public void addItem(Integer[] list, int item) {
list[1] = item;
}

Вы увидите изменения в списке из вызывающего кода. Однако вы не можете изменить саму ссылку, поскольку она передается по значению:

// assuming you allocated the list
public void changeArray(Integer[] list) {
list = null;
}

Если вы передаете ненулевой список, он не будет равен нулю к моменту возврата метода.

Ответ 4

Нет, это неправильно. Массивы - это особые объекты в Java. Таким образом, это похоже на передачу других объектов, где вы передаете значение ссылки, но не саму ссылку. Это означает, что изменение ссылки на массив в вызываемой подпрограмме не будет отражено в вызывающей подпрограмме.

java arrays