Рубрики
Без рубрики

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

Когда дело доходит до Java при вызове метода и передаче аргументов в качестве примитивов, в этом нет сомнений… С тегами java, c, cpp.

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

В связи с этим возникает вопрос: Передается ли Java по ссылке, когда речь заходит о ссылочных типах?

Переменные Прежде чем перейти к обсуждению передачи по значению/ссылке, давайте разберемся, какие переменные, кроме стандартной переменной, были доступны программистам на языках, предшествовавших Java.

Указатели — В C/C++ существуют переменные специального типа, в которых хранится адрес переменной любого типа, называемой Указателями. Указателям обычно присваивается адрес другой переменной или они сделаны так, чтобы указывать ни на что (НУЛЕВОЙ указатель). Указатели – это ссылочные типы в Java.

Ссылочные переменные — В C++ существует другой специальный тип переменной, который действует как псевдоним/альтернативное имя исходной переменной, называемый ссылочной переменной. Таким образом, любое изменение исходной переменной или ее псевдонимов влияет на все. Ссылочные переменные объявляются с помощью оператора & и должны быть инициализированы во время создания, так как он не принимает значение NULL.

Посмотрите на приведенный ниже пример кода на C++. Обратите внимание, что операторы * и & имеют разные функциональные возможности в объявлении и выражении.

#include 
using 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 — Эта функция принимает две ссылочные переменные и меняет их местами.

  • замена Путем Разыменования Указателя — Эта функция принимает две переменные указателя и разыменовывает их, используя адрес.

#include 
using 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”