Java is a pass-by-value language - and (to test yourself) do you understand what that means?

One day, some time ago, while I was searching through the web for an answer to something (not surprisingly) code related, I somehow stumbled upon a thread over at Stack Overflow. I cannot find the original post at the moment, but basically the author presented a piece of code and asked why it didn't work. Another developer replied and said it was due to that Java is a pass-by-value language and not pass-be-reference.

Test yourself first

Even though I don't have his original code, I have written my own version below. But before I explain what a pass-by-value actually means, look at this code below and try to answer two questions: What will it print? And more importantly do you
understand why?

public class Test {

    public static void main(String[] args) {

        Person p = new Person();
        p.setName("Alice");

        build(p);

        System.out.println(p.getName());

    }

    public static void build(Person p) {

        p.setName("Bob");
        p = new Person();
        p.setName("Christy");

    }

}

class Person {

    private String name = "";

    public void setName( String name ) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

The correct answer is "Bob". If you thought it was "Christy", trust me - you are not alone. It's a common mistake.

Let me explain how it works.

Pass-by-value vs Pass-by-reference: The business card example

As you have been taught that in school Java manipulate objects by reference and all object variables are references. However To try and explain this with strings to the real world, lets say there is a business man called Fred. In Java you could say that Fred is an instance object of the BusinessMan class:

new BusinessMan("Fred");

In your pocket you find his business card with Fred's phone number The business card is obviously not Fred himself, but just a pointer to him - just as a reference variable in Java towards an object. The variable is not the object but only simply an arrow or a link to the object:

BusinessMan businessCard = new BusinessMan("Fred");

So when you give (pass) the business card to someone else (call a method) you don't give them Fred himself, but a business card (reference) to Fred, containing the information where Fred is.

But here is the distinction between pass-by-value and pass-by-reference. When you give the business card you don't actually give them your business card. You make a copy of the business card and give them the copy. Meaning now have two business cards pointing to Fred. This is pass-by-value. If you actually gave them the business (and not make a copy) it would be pass-by-reference.

Now if you point your own business card (not the copy you created) to some other business man (maybe by scratching over Fred's phone number and and writing Ken's instead), there would be still a business card pointing towards Fred - the one you copied and gave away.

A graphical explanation of the code

I our code we created a new variable reference "p" and point it towards a new instance of Person and set the variable "name" to "Alice".

Person p = new Person();
p.setName("Alice");

Then we call the method "build" which create a new variable (also called "p") and copies the original "p"’s value reference. This leaves us with two variables called "p" that are pointing towards the same Person, however the second "p" only exists inside the method "build".

Next we rename the name "Alice" to "Bob"

p.setName("Bob");

Hold on, doesn't this prove that Java is a pass-by-reference language?

Here is a common trap for new Java developers. Since we obviously manage to rename the person from "alice" to "bob" in our method, but the change is also viewable outside the method, doesn't this mean Java is actually a pass-by-reference language?

No, not really. Everything in Java is passed as values. When you send an object to a method, you actually don't send the reference, nor the actual object. You simply send the value of the reference, not the reference it self.

This means that even though you can rename "alice" to "bob", you can't replace the original "p" outside the method by doing "p = new Person()" - as I will demonstrate below.

Continuing with the graphical example

But now we create a second Person, point the method variable "p" towards it and call them "Christy".

p = new Person();
p.setName("Christy");

This means there are now two variables (both called "p") pointing towards two different Person-objects.

So when we, outside the method, get the original "p"’s name (which did however get changed from "Alice" to "Bob" inside the method) we are referring towards the first Person.

System.out.println(p.getName());

Resulting in that "Bob" will be printed.

How to pass-by-reference in Java

Java is strictly a pass-by-value language, meaning Java does not pass method arguments by reference but as values. This is even stated in the language specifications.

However there are situations where you would like to pass-by-reference inside the method, for example you actually want to change the variable outside - inside the method.

The best solution is to create a generic wrapper class around the object and call the method with that as the argument instead. This would allow you to re-point the actual object via the wrapper class.

public class Ref {

    private T obj;

    public Ref(T value) {
        this.obj = value;
    }

    public void set(T value) {
        obj = value;
    }

    public T get() {
        return obj;
    }

}

Old comments from Blogger

Markus January 31, 2011 at 7:35 PM

I hate to break it to you, but java IS a pass-by-reference language. If it wasn't, you couldn't change "Alice" to "Bob" the way you did. The link to the JLS that you've posted talks about syntax, not variable passing.

Christoffer Pettersson February 6, 2011 at 2:13 AM

Hey Markus.

This whole subject is a bit tricky to understand.

If Java was pure pass-by-value, if you send in "p" into "build" then you would create a new object which only would exist in the method. Like with primitive data types. And if you do "setName()" it would only change the object inside the method and not the "p" outside the method.

But since "setName()" actually modifies the "p" outside method as well, it has to be pass-by-reference, right?

Well, not quite. What's passed is (this is where it gets confusing) the value of the reference, not the reference itself. Otherwise "p = new Person();" would have rewritten the "p" outside method - but it doesn't.

Java copies and passes the reference by value, not the reference itself, nor the actually value - but the reference as a new copied value.

Thanks for your comment, and I will change and clarify this in my post :-)

Markus February 6, 2011 at 8:56 AM

I'm afraid you're still wrong. You're confusing references with pointers. Had this been C, you could have done what you say, namely do p = new Person() (if C had supported the same syntax), and have the outer 'p' get the new person as well. You also need to be careful about sentences like "the value of the reference". The value of the reference as you interpret it is akin to the number that represents toe pointer location. What I believe most people would think about when they here "the value of the reference" is the actual value pointed to, in this case the person. What you're talking about is what I most languages use, which is to copy the reference to the stack frame of the method called. Just because a copy takes place doesn't mean you're passing by value. That's just passing.

Calling java pass-by-value is wrong, and you're likely to confuse readers if you do. Since you make the distinction between "pure pass-by-value" and what you claim java uses, then please don't claim that java is pass-by-value in your main article, since you refute yourself here in the comments.

Christoffer Pettersson February 6, 2011 at 9:45 AM

Hey Markus.

Calling it "pure pass-by-value", might be a confusing statement. With "pure pass-by-value" I meant that if you send an object through a method, you would send the actual object.

However, Java is a "pass-by-value" language, meaning values (and only values) are sent. Java sends in object references as values, instead of the actual reference.

That's why when you do "setName()" you modify the original object outside the method, but also why "p = new Person()" does not replace the original reference "p" outside the method.

Regarding pointers, Java actually has pointers, but they are called "references" instead (different name, same thing). According to the JLS (Java Language Specification) at http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.3.1 it says:

"The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object."

Do you have any articles or other work that says that Java is a pass-by-reference, and not pass-by-value language? I am interesting to know what you base your claim that Java is a pass-by-reference language on?

Markus February 6, 2011 at 10:02 AM

We're both right, in a way. The reference itself is passed by value. What you as a developer get to use, or you as a method body,

perhaps, however is the external object pointed to by the reference you were passed. That, to me, and to most practitioners, is pass by reference.

Nimnio January 23, 2012 at 7:04 PM

Markus: "That, to me, and to most practitioners, is pass by reference."

Actually, in the Stack Overflow question Christoffer is referring too, calling this "pass by value" had the most votes at 258, and all of the close runner ups say the same thing. It appears that "most practitioners" call this pass by value.

http://stackoverflow.com/questions/40480/is-java-pass-by-reference

Nimnio January 23, 2012 at 7:09 PM

That said, my first guess was pass by reference. Upon reading the explanation, I understand that the difference

between "pass by reference" and "pass by value" is more subtle than simply "can I alter the object?", and it is a useful distinction.