limitless
limitless

Reputation: 669

Why does this program output 1?

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

Answers (3)

T.J. Crowder
T.J. Crowder

Reputation: 1074425

First of all, in foo(myObject) we are assigning something to final, 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 get myObject to be null, so how can we even print it?

There are two separate things called myObject in your code:

  1. A variable in main

  2. 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

apetranzilla
apetranzilla

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

Jaims
Jaims

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

Related Questions