Does passing objects in Java simulate passage by reference?

7

Everyone says that Java goes by value, including Objects. These are passed by copy and can not be reassigned to a new object within the method. The problem is that it is possible to change the value of objects within the method. Does not this characterize pass-by-reference simulation (made with C ++ pointers)?

Java Code Example

class Objeto {

    public int valor;

    public Objeto(){

        this.valor = 2;
    }   
}

public class Passagem {

    public static void main(String[] args) {

        Objeto obj = new Objeto();

        System.out.printf("Valor inicial: %d\n", obj.valor);

        metodo(obj);

        System.out.printf("Valor após o método: %d\n", obj.valor);

        metodoNovo(obj);

        System.out.printf("Valor após o método com novo objeto: %d\n", obj.valor);


    }

    // Simula a passagem por referência alterando o valor do objeto
    // mas não o local de memória para qual aponta
    static void metodo(Objeto obj){

        obj.valor = 5;
    }

    //Tenta alterar o objeto em si
    static void metodoNovo(Objeto obj){

        obj = new Objeto();

        obj.valor = 10;         
    }
}

The value of the object can be directly changed by the first method. Already in the second it is not possible to reassign it to a new object, even because the method expects to receive a constant object - to change an object itself logic says that we would have to have an object for an object .

The example in C ++, which behaves in the same way:

Code Example in C ++

#include <iostream> 

using std::cout;
using std::endl;

class Objeto{

    public:
        int valor;

        Objeto(){

            this->valor = 2;
        }
};

void funcao(Objeto *obj){

    obj->valor = 5;
}

void funcaoNovo(Objeto *obj){

    obj = new Objeto();

    obj->valor = 10;
}

int main()
{
    Objeto *obj = new Objeto();

    cout << "Valor inicial: " << obj->valor << endl;

    funcao(obj);

    cout << "Após função: " << obj->valor << endl;

    funcaoNovo(obj);

    cout << "Após função que atribui novo objeto: " 
        << obj->valor << endl;
}

The result of the two codes is the same.

It is only possible to change the object itself in C ++ code if the function expects to receive the address of the object itself, as in:

C ++ Function Changing Object

void funcaoNovo(Objeto **obj){

    *obj = new Objeto();

    (*obj)->valor = 10;
}

main for the above function

int main()
{
    Objeto *obj = new Objeto();

    cout << "Valor inicial: " << obj->valor << endl;

    funcao(obj);

    cout << "Após função: " << obj->valor << endl;

    funcaoNovo(&obj);

    cout << "Após função que atribui novo objeto: " 
        << obj->valor << endl;
}

Where you can see that the reallocation worked out.

Based on these comparisons, is it safe to say that in Java there is also a passing-through simulation ? You can not change the object (the location it points to), but you can change its values because the calling function (or method) directly changes the value of the values in the objects.

Note: In C you can also do the same test. A given function funcao(int *ptr) can not assign ptr to a new malloc within it. Only the value can be changed and is considered a passing simulation by reference.

My biggest question:

In C ++ the object itself does not change the original value.

void funcaoNovo(Objeto *obj){

    Objeto *novo = new Objeto();

    novo->valor = 10;

    obj = novo;
 }

Here the obj is not changed outside the function. Just like in Java.

In other words, you can not reassign an object either because C ++ can not change the object passed by copy as well. However you can change the value contained in the object (here is the simulation), as long as you do not try to change the object.

This is called passing simulation by reference, because the calling function modifies the data contained in Object and not the Object itself. Java does not have reference passing (except with arrays), but would not it be correct to say that there is a simulation of this passage in the value for which the object reference , ie I get a simulation when referencing the values?

I see that both passages are similar - they allow the function to change values out of scope (including multiple values), without allowing pointer reassignment (Java reference).

    
asked by anonymous 21.04.2015 / 15:52

2 answers

9

"References" and " pass by reference " are two distinct things. Unlike C / C ++, in Java every variable that refers to a complex object does so through a reference, not a pointer, not a value type.

C / C ++

The three main ways of manipulating objects:

Objeto valor; // Um objeto no stack
Objeto* ponteiro = &valor; // Um ponteiro para um objeto no stack ou no heap
Objeto& referencia = valor; // Uma referência para um objeto no stack ou no heap

The way to use them is different: with value types and references, one can access the object's members directly, while with the pointers it is necessary to "derrefer" them:

cout << "Valor inicial: " << valor.valor << endl;
cout << "Valor inicial: " << (*ponteiro).valor << endl;
cout << "Valor inicial: " << referencia.valor << endl;

// Atalho para ponteiros (derreferenciação e acesso num único operador)
cout << "Valor inicial: " << ponteiro->valor << endl;

When passing them to a function, the value type causes a copy of the entire object:

void prop1(Objeto arg) {
    arg.valor = 5; // Não afeta o objeto original
}

void redef1(Objeto arg) {
    Objeto novo;
    novo.valor = 10;
    arg = novo; // Não afeta o objeto original
}
The pointer does not copy the object, but as it simply "points" to some object, changing its value will simply point it to some other object - not affecting the original object:

void prop2(Objeto* arg) {
    arg->valor = 5; // Afeta o objeto original
}

void redef2(Objeto* arg) {
    Objeto* novo = new Objeto();
    novo->valor = 10;
    arg = novo; // Não afeta o objeto original
}

The reference "refers" to the original object. Any change in it will affect the original, either by moving its properties, or by reassigning it:

void prop3(Objeto& arg) {
    arg.valor = 50; // Afeta o objeto original
}

void redef3(Objeto& arg) {
    Objeto novo;
    novo.valor = 100;
    arg = novo; // Afeta o objeto original
}

Alternative:

Objeto& referencia2 = *(new Objeto()); // Uma referência para um objeto no heap

void prop4(Objeto& arg) {
    arg.valor = 50; // Afeta o objeto original
}

void redef4(Objeto& arg) {
    Objeto* novo = new Objeto();
    novo->valor = 100;
    arg = *novo; // Afeta o objeto original
}

Example on Ideone . Disclaimer: I have almost no practical experience with C / C ++, do not see the above code as a good way to program in these languages (including, I'm almost sure you have at least one memory leak in this code ...).

Java

In Java, value types and pointers do not exist, and a reference has some things in common with each of the three:

  • The syntax of the variable is similar to the value type:

    Objeto referencia;
    
  • The construction with the pointer:

    = new Objeto();
    
  • And the semantics of the final result is similar (but not identical) to that of the reference:

    Objeto referencia = new Objeto();
    
  • However, references are passed by value :

    void prop(Objeto arg) {
        arg.valor = 5; // Afeta o objeto original
    }
    
    void redef(Objeto arg) {
        Objeto novo = new Objeto();
        novo.valor = 10;
        arg = novo; // Não afeta o objeto original
    }
    

What this means, in the end, is that in Java every variable of a complex type contains not the object itself, but a reference (which can or can not be implemented through a pointer - see this answer for more details) for the actual object - which only exists in the heap . This reference can be copied to other variables, which means that they also refer to the same object.

Accessing an object by any of its references has the same effect. However, the references themselves are independent of each other. They are copies of each other. And moving a copy does not change the original. This is why assigning a value to a reference (i.e. making it point to another object) has no effect on the other references to that object - which continue to point to the original object.     

21.04.2015 / 16:50
1

Almost all (if not all) object-oriented languages actually pass always objects by "reference" - That is - all that methods or functions that receive objects as parameters receive is a reference to the original object that is usually represented internally by a memory address (a pointer) - although in some higher-level languages such as Java and Python, unlike C ++, the fact that its method receives a memory address is so transparent to the programmer that it is "invisible".

This is why when you access attributes or methods of the object, in those languages the syntax is the same - unlike C and C ++ where you have to write your code in a way if you have the "value" of the data structure / object or with another notation if it has a "reference". In practice it is as if in these languages you always have a reference to the object - even in the place where it is declared and created.

And why then you can not change the object itself that is referred to? Why the name of the variable that receives the object is in the target function or method - and points to a specific object. If you point the name to another object, the method that called your code has no way of knowing that. On the other hand, if you make changes to the received object, you are actually changing the same object that the caller of the current method is "seeing."

In fact, out of C, it does not make much sense for you to worry if you're going through "reference" or "value" most of the time - you need to know you're passing an object from side to side.

    
21.04.2015 / 16:50