简体   繁体   中英

Parameters passing in Java

I have a Long object in a class, I give it a value and then I pass it to another class' constructor, where it is changed. Why are the changes NOT visible in the first object?

The code:

public class ClassA {
    private Long t;

    public ClassA() {
        t = new Long(10);
        System.out.println(t); // prints 10
        new ClassB(t); // it is modified (see ClassB)
        System.out.println(t); // prints 10 again
    }

    public static void main(String[] args) {
        new ClassA();
    }
}

class ClassB {
    private Long p;

    public ClassB(Long p) {
        this.p = p;
        this.p = this.p + 1;
        System.out.println(this.p); // prints 11
    }
}

The output is: 10 11 10 The Long variable is initialized in ClassA. Then I pass it to ClassB, modify it and clearly the changes are not visible in the first class. Why?

It is because the Long class is immutable; once an instance is created, it can never change.

In this line:

this.p = this.p + 1;

what you are doing is create a new Long object. Other examples of immutable classes include all "wrapper" classes for primitive numeric types ( Byte , Short etc) and String .

What doesn't help is that it makes the + operator unintuitive; what really does not help is that the language allows + on all of these immutable classes.

What happens in the above line could be written as (although it happens differently in the bytecode, I suspect):

long tmp = this.p.longValue();
tmp += 1;
this.p = new Long(tmp);

You can also verify immutability by marking your p as final in class B , which means the reference p can never change; this.p = this.p + 1 will raise a compile error since you attempt to modify reference p .

this line this.p = this.p + 1; does not modify p, it creates a new Long from adding the two values p and 1 and then sets this.p to be a reference to this new Long . Objects of the class Long do not have mutator methods so they can never change (within Class B this.p was not changed, this.p became a reference to a new Long)

So the behaviour is actually

this.p=p;
Long newLong=this.p + 1;
this.p=newLong;

What you're imagining is

this.p=p
this.p.imaginaryAddLocal(1);

this would effect the original p, but of course this method imaginaryAllLocal doesn't exist because objects of the class Long are immutable

To begin with, Long is immutable. It means you cannot change the value that you set in the constructor (note the absence of set methods).

When you do

this.p = this.p + 1;

Java does.

1) Autoconvert this.p to its long value (primitive)

2) Arithmetic operation

3) Autoconvert the result back to a new, different Long and assign the reference to this.p

t continues pointing, all the time, to the original Long object.

In Java, you modify objects through its attributes (not adviceable, you should make them private ) or its methods. A + (or other operator) will never change an object state (although it may create a new one, in the only case of myString1 + myString2 )

1- You are just modifying the p member of class B
2- Everything is passed by value (and not by reference) in Java

The Long class is immutable, so you can not pass back the value by modifying it in the called function. In your ClassB a copy is created and the original value is never changed.

If you want the caller to see the changed value, you must pass it back as return value.

The same is true for the other primitive wrappers and String.

Because Java uses pass-by-reference. This means that it passes a copy of the variable, and not a reference to the "original" one.

Eg in C++, you can do this:

void change_var(int &x)
{
    x = 2;
}

int x = 10;
change_var(x);
std::cout << x << std::endl;

This would print 2 , since the reference to the variable x is being passed, and not a copy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM