Когда дело доходит до Java при вызове метода и передаче аргументов в качестве примитивов, нет сомнений в том, что он следует модели передачи по значению. Проблемы с пониманием возникают, когда имеешь дело с Объектами. Поскольку ссылочные типы хранят адрес объекта, когда ссылочные типы передаются в качестве аргументов, передается адрес памяти объекта, и любое изменение природы объекта (переменных экземпляра) внутри вызываемого метода отражается в вызывающем.
В связи с этим возникает вопрос: Передается ли Java по ссылке, когда речь заходит о ссылочных типах?
Переменные Прежде чем перейти к обсуждению передачи по значению/ссылке, давайте разберемся, какие переменные, кроме стандартной переменной, были доступны программистам на языках, предшествовавших Java.
Указатели — В C/C++ существуют переменные специального типа, в которых хранится адрес переменной любого типа, называемой Указателями. Указателям обычно присваивается адрес другой переменной или они сделаны так, чтобы указывать ни на что (НУЛЕВОЙ указатель). Указатели – это ссылочные типы в Java.
Ссылочные переменные — В C++ существует другой специальный тип переменной, который действует как псевдоним/альтернативное имя исходной переменной, называемый ссылочной переменной. Таким образом, любое изменение исходной переменной или ее псевдонимов влияет на все. Ссылочные переменные объявляются с помощью оператора & и должны быть инициализированы во время создания, так как он не принимает значение NULL.
Посмотрите на приведенный ниже пример кода на C++. Обратите внимание, что операторы * и & имеют разные функциональные возможности в объявлении и выражении.
#includeusing namespace std; int main(){ int var = 45; //Simple variable , stores 45 as its value int* varPtr = &var //Pointer variable , stores the address of var as its value int** varPtrPtr = &varPtr //Pointer variable , double pointer, stores the address of varPtr as its value int& varRef = var; //Reference variable, acts as a reference to var int* varRefPtr = &varRef //Pointer variable , stores the address of varRef as its value cout << "\nvar : " << var; cout << "\nvarPtr : " << varPtr; cout << "\nvarPtrPtr : " << varPtrPtr; cout << "\nvarRef : " << varRef; cout << "\nvarRefPtr : " << varRefPtr; } /* * * Sample Output * -------------------- * var : 45 * varPtr : 0x61fdb4 * varPtrPtr : 0x61fda8 * varRef : 45 * varRefPtr : 0x61fdb4 * * */
Из приведенного выше вывода мы видим, что VarPtr сохраненный адрес var в то время как var Ref сохранял значение var. Аналогично, адрес varref т. е. varRefPtr идентичен адресу var т. е., VarPtr . Это доказывает, что указатели и ссылочные переменные концептуально различны.
Передавать по значению и передавать по ссылке в C++ Теперь, когда мы поняли различные типы доступных переменных, давайте посмотрим пример программы подкачки на C++, использующей эти различные переменные. Вот краткое описание различных функций в программе.
swapByValue — Эта функция принимает две простые переменные и меняет местами, используя временную переменную.
swapByPointer — Эта функция принимает две переменные указателя и пытается поменять местами. Обратите внимание, что здесь разыменование указателя не используется для отображения разницы между переменными указателя и ссылки.
swapByReference — Эта функция принимает две ссылочные переменные и меняет их местами.
замена Путем Разыменования Указателя — Эта функция принимает две переменные указателя и разыменовывает их, используя адрес.
#includeusing namespace std; void swapByPointerDereference(int* a4, int* b4){ cout << "\nEnters : a4 value is " <
Вывод ясно показывает, что только во время выполнения подкачки по ссылке подпрограммы значение и адрес переменных остались прежними. Хотя Разыменование по указателю функция поменяла значения местами, они просто использовали передачу по значению с адресом и выполнили разыменование. Это видно из разницы в адресах переменных между вызывающей и вызываемой функциями. Таким образом, это доказывает, что только через ссылочные переменные можно использовать передачу по ссылке.
Передавать по значению или передавать по ссылке в Java В Java нет таких переменных, как ссылочные переменные. Ссылочный тип, в котором хранится адрес объекта, является просто указателем на объект.
Давайте посмотрим программу подкачки, аналогичную той, что была показана выше на языке Java. Программа может содержать три метода, и они выполняют следующие действия,
- swapByValue — Метод, который меняет местами два примитива
- swapByReferenceType — Метод, который меняет местами два ссылочных типа
- swapByObjectManipulation — Метод, который меняет объекты местами, выполняя что-то похожее на разыменование указателя с помощью оператора Java dot
class Person { int id; String name; Person(int id, String name){ this.id = id; this.name = name; } } public class PassByModel { public static void main(String... args) { Person p1 = new Person(1, "Person1.0"); Person p2 = new Person(2, "Person2.0"); Person p3 = new Person(3, "Person3.0"); Person p4 = new Person(4, "Person4.0"); int a = 1, b = 2; System.out.println(); System.out.println("*-----Swap By Value-----*"); System.out.println("Before : a is "+a+", b is "+b); swapByValue(a, b); System.out.println("After : a is "+a+", b is "+b); System.out.println(); System.out.println("*-----Swap By Reference Type-----*"); System.out.println("Before : p1 is "+p1+", p2 is "+p2); System.out.println("Before : p1 id is "+p1.id+", p1 name is "+p1.name+"; p2 id is "+p2.id+", p2 name is "+p2.name); swapByReferenceType(p1, p2); System.out.println("After : p1 is "+p1+", p2 is "+p2); System.out.println("After : p1 id is "+p1.id+", p1 name is "+p1.name+"; p2 id is "+p2.id+", p2 name is "+p2.name); System.out.println(); System.out.println("*-----Swap By Object Manipulation-----*"); System.out.println("Before : p3 is "+p3+", p4 is "+p4); System.out.println("Before : p3 id is "+p3.id+", p3 name is "+p3.name+"; p4 id is "+p4.id+", p4 name is "+p4.name); swapByObjectManipulation(p3, p4); System.out.println("After : p3 is "+p3+", p4 is "+p4); System.out.println("After : p3 id is "+p3.id+", p3 name is "+p3.name+"; p4 id is "+p4.id+", p4 name is "+p4.name); } static void swapByValue(int a, int b) { System.out.println("Enters : a is "+a+", b is "+b); int temp = a; a = b; b = temp; System.out.println("Exits : a is "+a+", b is "+b); } static void swapByReferenceType(Person p1, Person p2) { System.out.println("Enters : p1 is "+p1+", p2 is "+p2); Person temp = p1; p1 = p2; p2 = temp; System.out.println("Exits : p1 is "+p1+", p2 is "+p2); } static void swapByObjectManipulation(Person p3, Person p4) { System.out.println("Enters : p3 is "+p3+", p4 is "+p4); Person temp = p3; p3.id = p3.id; p3.name = p3.name; p4.id = temp.id; p4.name = temp.name; System.out.println("Exits : p3 is "+p3+", p4 is "+p4); } } /* * Sample Output * ------------- * * *-----Swap By Value-----* * Before : a is 1, b is 2 * Enters : a is 1, b is 2 * Exits : a is 2, b is 1 * After : a is 1, b is 2 * * *-----Swap By Reference Type-----* * Before : p1 is Person@18e8568, p2 is Person@33e5ccce * Before : p1 id is 1, p1 name is Person1.0; p2 id is 2, p2 name is Person2.0 * Enters : p1 is Person@18e8568, p2 is Person@33e5ccce * Exits : p1 is Person@33e5ccce, p2 is Person@18e8568 * After : p1 is Person@18e8568, p2 is Person@33e5ccce * After : p1 id is 1, p1 name is Person1.0; p2 id is 2, p2 name is Person2.0 * *-----Swap By Object Manipulation-----* * Before : p3 is Person@326de728, p4 is Person@25618e91 * Before : p3 id is 3, p3 name is Person3.0; p4 id is 4, p4 name is Person4.0 * Enters : p3 is Person@326de728, p4 is Person@25618e91 * Exits : p3 is Person@326de728, p4 is Person@25618e91 * After : p3 is Person@326de728, p4 is Person@25618e91 * After : p3 id is 3, p3 name is Person3.0; p4 id is 3, p4 name is Person3.0 * */
Методы swapByValue |/и обмен По Ссылке производят аналогичный вывод. Несмотря на то, что ссылочный тип содержит адрес объекта в качестве его значения (Персона), значение просто присваивается параметру, и эти параметры не являются прямыми ссылками на объект, созданный в вызывающем объекте. Язык Java не позволяет программисту создавать ссылочные переменные. Из приведенного выше эксперимента можно сделать вывод, что передача по ссылке на самом деле никогда не допускается в Java.
Java разработана с использованием C в качестве фундаментальной модели программирования и C++ для принципов ООП. Java передает значения методам, и эти значения просто копируются между параметрами, будь то примитивы или ссылочные типы. Часто неправильно понимают, что, поскольку ссылочные типы хранят адрес объекта, он передается по ссылке. Ссылочные типы являются указателями, а не ссылочными переменными. На самом деле, в Java нет ссылочных переменных или псевдонимов/альтернатив, как в C++.
Отвечая на вопрос, Java передает только по значению как для примитивов, так и для ссылочных типов!!!
Полезные ссылки по теме Полезные ссылки по теме https://stackoverflow.com/questions/1961146/memory-address-of-variables-in-java https://stackoverflow.com/questions/14612314/how-are-variable-names-stored-in-memory-in-c https://stackoverflow.com/questions/14612314/how-are-variable-names-stored-in-memory-in-c
Оригинал: “https://dev.to/vivekworks/does-java-pass-only-by-value-3l7l”