Reputation: 669
I've looked at this code and I don't understand why this program will print 1
.
First of all, in foo(myObject)
we are assigning something to final, how is this possible?
And the second thing, after foo()
was done, we'll get myObject
to be null, so how can we even print it?
public class MyClass {
private int myInt;
public static void foo(MyClass myObject) {
myObject.myInt = 1;
myObject = null;
}
public static void main(String[] args) {
final MyClass myObject = new MyClass();
myObject.myInt = 2;
foo(myObject);
System.out.println(myObject.myInt);
}
}
Upvotes: 2
Views: 109
Reputation: 1074425
First of all, in
foo(myObject)
we are assigning something tofinal
, how is it possisble?
The object is not final
, the variable in main
is final
. So in main
, if you added myObject = somethingElse;
after your initial line that sets its value, it wouldn't compile because you can't put a new value in the variable. That has no effect on whether the object the variable refers to is mutable.
And the second thing, after
foo()
was done, we'll getmyObject
to be null, so how can we even print it?
There are two separate things called myObject
in your code:
A variable in main
A parameter in foo
Your code in foo
sets the parameter to null
, but that has no effect whatsoever on the variable in main
. (In fact, it's impossible for foo
to have any effect on the variable in main
; Java is a purely pass-by-value language. All foo
can do, as you've demonstrated, is modify the state of the object that both the variable and the parameter refer to, using the object reference passed into it as a parameter.)
Let's stop your code just before this line in foo
:
myObject.myInt = 1;
Here's what we have in memory (leaving out some details and irrelevancies):
+−−−−−−−−−−−−−−−−−−−−−−+ | variable "myObject" | foo can change the +−−−−−−−−−−−−−−−−−−−−−−+ *state* of this foo can't change this−−>| Ref22458 |−−−+ | +−−−−−−−−−−−−−−−−−−−−−−+ | v | +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+ +−−−>| object of type MyClass | | parameter "myObject" | | +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+ | | myInt: 2 | foo can change this−−−−>| Ref22458 |−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+
...where "Ref22458" is just a name for the value of the object reference that points to the object you created in main
.
Once we execute the two lines in foo
:
myObject.myInt = 1;
myObject = null;
we have this in memory:
+−−−−−−−−−−−−−−−−−−−−−−+ | variable "myObject" | foo can change the +−−−−−−−−−−−−−−−−−−−−−−+ *state* of this foo can't change this−−>| Ref22458 |−−−+ | +−−−−−−−−−−−−−−−−−−−−−−+ | v | +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+ +−−−>| object of type MyClass | | parameter "myObject" | | +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+ | | myInt: 1 | foo can change this−−−−>| null |−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+
Note how foo
could change the state of the object (myInt
is now 1
), and could change the value in the parameter myObject
(it's now null
), but couldn't change the value in the variable myObject
(for two reasons: it has no access to the variable [Java is pass-by-value], and the variable is final
).
Upvotes: 10
Reputation: 5949
final
just specifies that the object itself should not change - when used with classes like your code it just prevents someone from doing myObject = ...
. Unless you mark MyClass.myInt
final, you will be able to assign whatever value to the int that you want, even after assignment.
The way to solve this is to make myInt
private and provide a public getter for it instead, preventing it from being modified (except by reflection)
Upvotes: 0
Reputation: 1575
Java is not pass by reference (references are passed by value), assigning myObject
to null
does not make a difference. It is not final
neither, because it is not made final inside your foo()
method. It prints 1, because you pass the reference of myObject
into foo()
and set its field. It's still a mutable object, so its value is updated.
Upvotes: 0