Java: Passing by Reference With a Twist

Currently I’m teaching a Java class online, and Vitaly O., one of my students, ran into an interesting situation. He sent me the program below, which, to his surprise, printed 1.

public class Main {

    public static void main(String[] args) {
        Integer t = new Integer(0);
        t=1;
        test(t);
        System.out.println(t);
    }
   
    public static void test(Integer t) {
    	t=2;
    }

}

The topic of passing by value vs by reference is one of the difficult topics to understand for Java beginners. The code above can confuse junior Java developers, because the author of the program above ran into a bouquet of Java features, which I’ll explain (slowly) in this blog.

All Java textbooks (mine included) will tell you that objects are being passed by reference and primitives by value. That’s fine and understandable – nobody wants to copy large objects in memory . But what about the variables that point at an object and are being passed to a method as arguments like in test(t) line above?
First, let’s take care of a simpler case. Let’s replace the Integer with the class Car that looks like this:

public class Car {
   int salesmanWhoHasKeys;
} 

Imagine a tiny car dealership with two salesmen that has a room only for one car. When a customer pops in, one of the salesmen takes the car keys to test drive THE car. The class TestCar will look similar to the class Main, but is not exactly the same.

public class TestCar {

    public static void main(String[] args) {
        Car t = new Car();
        t.salesmanWhoHasKeys=1;
        
        test(t);
        System.out.println(t.salesmanWhoHasKeys);
    }
   
    public static void test(Car t) {
    	t.salesmanWhoHasKeys=2;
    }
}

The program TestCar prints 2. Why? What makes it different from the program Main? Just bear with me for a moment. Let’s completely understand what the phrase “objects are passed by reference” means. There is only one car, remember? And Java doesn’t create a copy of the one and only instance of the object Car just to pass it to the method test(). But it does create a copy of the original pointer t inside the method test for method argument, which (to add to the confusion) is also named t.

Get used to the fact that we have one object in memory with two different pointers to it (t and ttt). To make things easier to understand, modify the method test() to look as follow:

   public static void test(Car ttt) {
    	ttt.salesmanWhoHasKeys=2;
    }

The program still prints 2. So what’s the difference between dealing with the instance of a Car vs Integer? The wrapper class Integer is immutable. This means that you can’t change its value once it was assigned, which is not the case with the Car.
To make things worse for comprehension, the Java feature called autoboxing kicks in and the original program quietly creates instances of new wrapper Integer objects when it sees something like t=2. This line gets converted into t=new Integer(2)! Got it? So the value 2 has been assigned to a different Integer object via a different variable t.

And just to make sure that you clearly understand the whole confusion of the program Main, please answer my final question, “How many instances of the class Integer were created during the lifespan of the program Main?”

Who said two? Mary? Wrong! The right answer is three! The first one had the value of zero, the next line caused the creation of the another instance if Integer with the value of 1, and the third instance was created by the method test() with the value of 2. Don’t believe me? Step through the Main program in a debugger, and you’ll see three different ids assigned to the variable t.

Don’t you love Java? I do.

Advertisement

4 thoughts on “Java: Passing by Reference With a Twist

  1. Passing by reference in Java and PHP:

    “By reference” in Java:

    class Test {
    private int a;
    Test(int a){this.a=a;}
    public String toString(){return “”+a;}
    }

    public class Main {
    public static void main(String[] args) {
    Test t1 = new Test(1);
    System.out.println(t1);
    test(t1);
    System.out.println(t1);
    }
    public static void test(Test t)
    {
    System.out.println(“–“+t);
    t=new Test(2);
    System.out.println(“–“+t);
    }

    }

    Result:

    1
    –1
    –2
    1

    *In function `test` we passing variable by pointer copy

    ===============================

    “By reference” in PHP:

    <?php
    echo '

    ';
     
    class Test
    {
          private $a;
          public function __construct($a)  {$this->a = $a;}
          public function __toString() {return ''.$this->a;}
    }
     
    class Main {
          public function __construct()
          {
              $t1 = new Test(1);
              print $t1.PHP_EOL;
              $this->test($t1);
              print $t1.PHP_EOL;
          }
         
          public function test(&$t)
          {
              print '--'.$t.PHP_EOL;
              $t = new Test(2);
              print '--'.$t.PHP_EOL;
          }
    }
    $main = new Main;
     
    ?>
    
    Result:
    
    1
    --1
    --2
    2
    
    *In function `test` we passing variable by pointer
    
    ===============================
    
    My conclusion: Before you say that you know how it works in Java, try to do it.
  2. I definitely like a lot the Java Tutorial- 24 Hour Trainer. The material in the lessons is structured very logically for me and the accompanying videos and Try it sections make the learning experience quite entertaining. Thank you for having written and recorded this excellent tutorial!

    I was wondering if I could join the related practicaljava project on code.google.com. The How-to on the project’s home just says “Join this project by contacting the project owners, usually through participating in a mailing list”…

    1. Thank you, Cristina. Not sure where did you find the statement about joining the project. The code samples are available to everyone. Some people submitted their versions of solutions to the exercises, and I made them project committers. Other than that there is no special process of joining the project http://code.google.com/p/practicaljava/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s