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

Возможный дубликат:
Является ли Java "сквозной ссылкой" ?

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

Ответ 1

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

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

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

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

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

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

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

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

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

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

Связанный ТАК вопрос:

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

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

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

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

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

UPDATE

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


1. Nothing in the linked Q&A (Arrays in Java and how they are stored in memory) either states or implies that arrays are not objects.

Ответ 2

Everything in Java are passed-by value.. В случае массива (который не что иное, как объект), ссылка массива передается по значению.. (Так же, как ссылка на объект передается по значению).

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

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

Смотрите это сообщение..

Является ли Java 'pass-by-reference " или "пропуск по значению" ,

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

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

Ответ 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. Таким образом, это похоже на передачу других объектов, где вы передаете значение ссылки, но не саму ссылку. Значение, изменение ссылки массива в вызываемой подпрограмме не будет отражено в вызывающей процедуре.

Ответ 5

Все в Java передается по значению.

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

Посмотрите эту интересную статью для получения дополнительной информации...

Ответ 6

Окончательное обсуждение массивов находится в http://docs.oracle.com/javase/specs/jls/se5.0/html/arrays.html#27803. Это дает понять, что массивы Java являются объектами. Класс этих объектов определяется в 10.8.

В разделе 8.4.1 спецификации языка http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#40420 описать, как аргументы передаются методам. Поскольку синтаксис Java получен из C и С++, поведение похоже. Примитивные типы передаются по значению, как при C. Когда объект передается, ссылка объекта (указатель) передается по значению, зеркалируя синтаксис C передачи указателя по значению. См. 4.3.1, http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.3,

В практическом плане это означает, что изменение содержимого массива в методе отражается в объекте массива в области вызова, но переназначение нового значения для ссылки внутри метода не влияет на ссылку в вызове scope, который является именно тем поведением, которое вы ожидаете от указателя на структуру на C или на объекте на С++.

По крайней мере, часть путаницы в терминологии проистекает из истории языков высокого уровня до общего использования C. На предыдущих, популярных языках высокого уровня, напрямую ссылаясь на память по адресам, можно было избежать, насколько это возможно, и было сочтено, что задание языка обеспечивает слой абстракции. Это сделало необходимым, чтобы язык явно поддерживал механизм возврата значений из подпрограмм (не обязательно функций). Этот механизм является тем, что формально подразумевается при ссылке на "pass by reference".

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

Так как это часто может показаться единственной целью необработанных указателей в C, это создавать сбои в ошибках, последующие разработки, особенно Java, стремились вернуться к более безопасным средствам для передачи параметров. Однако доминирование C заставило разработчиков подражать знакомому стилю C-кодирования. Результатом являются ссылки, которые передаются аналогично указателям, но реализованы с большей защитой, чтобы сделать их более безопасными. Альтернативой был бы богатый синтаксис такого языка, как Ada, но это могло бы представить появление нежелательной кривой обучения и уменьшило бы вероятное принятие Java.

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

Ответ 7

Вид трюковой недвижимости... Даже ссылки передаются по значению в Java, следовательно, изменение самой ссылки связано с уровнем вызываемой функции. Компилятор и/или JVM часто превращают тип значения в ссылку.