2

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);
    }
}
azurefrog
  • 10,785
  • 7
  • 42
  • 56
limitless
  • 669
  • 7
  • 18
  • 3
    Because `myObject.myInt = 1`. What did you expect it to be? – bradimus Aug 02 '16 at 17:10
  • 2
    @bradimus It's not as simple as that... the object is being set to null before the print statement, which can cause confusion for those not familiar with Java. – Matthew Diana Aug 02 '16 at 17:13
  • Do you know how java pass the objects to another methods???? – ΦXocę 웃 Пepeúpa ツ Aug 02 '16 at 17:14
  • @MatthewDiana, you're right that there is potential confusion there, so I would think you might be more careful with your language. It is not *the object* that is being set null, but rather one *reference* to it. – John Bollinger Aug 02 '16 at 17:16
  • Possible duplicate of [Is Java "pass-by-reference" or "pass-by-value"?](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) – Tom Aug 02 '16 at 17:17
  • @Tom: Not on its own, no. (Part of the problem with two-part questions. :-) ) – T.J. Crowder Aug 02 '16 at 17:27
  • @T.J.Crowder And we all know that one should ask one question per post ;P. – Tom Aug 02 '16 at 17:30
  • @Tom: True that. :-) Sometimes it's hard for people to realize they're asking two questions. Here it seems like they did, though. – T.J. Crowder Aug 02 '16 at 17:34
  • @T.J.Crowder I'm sorry, I didnt know that 2 question in the same post was a problem. – limitless Aug 02 '16 at 17:41

3 Answers3

10

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

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

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.

Jaims
  • 1,515
  • 2
  • 17
  • 30
0

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)

apetranzilla
  • 5,331
  • 27
  • 34
  • But myObject = null is happning inside of foo(), isnt that an assiment to final ? – limitless Aug 02 '16 at 17:16
  • 4
    @limitless No. Those are distinct reference in distinct scopes. – bradimus Aug 02 '16 at 17:18
  • @limitless That only applies within the scope of `foo()`. You're not setting `myObject` that was declared as final in `main`, you're setting the argument `myObject` for the `foo` method. – apetranzilla Aug 02 '16 at 17:25