next up previous
Next: A few notes about Up: General notes on Java Previous: IDEs

Pass by reference, but not really

Every semester a new group of students gets caught up by the same thing in Java. They start out hearing ``Java is always pass by reference,'' and they do silly looking things like the following:

void foo(String t) { t = new String(``World'');}
String s = new String(``Hello''); foo(s);
System.out.print(s); //prints ``Hello''.  Why didn't it change?

In true pass by reference C++ this would have worked. But what is happening is not really pass by reference; it is pass by value, except what is being passed is a pointer. If you were to transfer the above to C++ it would look like

void foo(String *t) { t = new String(``World''); }
String *s = new String(``Hello''); foo(s);
cout<<*s<<endl; //prints ``Hello''. Hopefully obvious why

You can see in the second example that t is only a local copy of s. If you alter the value t is pointing at then s will see the change. However, if you point t at something else, s will never know. In this example there is actually no way for foo to change s, since Java Strings are immutable after creation. An error less obvious than the above is

void foo(String t) { t = t + ``World''; }

This looks like concatenation, not reallocation, but that `+' operator actually allocates a new String. The above is actually just a shortcut in Java for

void foo(String t) {
    StringBuilder temp = new StringBuilder();
    temp.append(t);
    temp.append(``World'');
    t = temp.toString();
}

It's important to realize what's going on in the background! Of course in the above example, foo still doesn't change t, but what you could do instead is

void foo(StringBuilder t) { t.append(``World''); }

This time, since t always points to the same location, the original value really is modified. In Java, ``pass by reference'' as C++ programmers tend to think of it always requires some kind of wrapper. In the last example, StringBuilder is a wrapper for a dynamically sized character tabular. There is a quick and dirty hack to get a similar effect without building an entire class wrapper; pass a 1 element tabular instead:

void foo(String[] t) { t[0] = new String(``World''); }

String s[] = new String[1];
s[0] = new String(``Hello'');
foo(s); //s[0]= ``World''

This works for a similar reason. t points to the same tabular in memory that s does. When an element of the tabular is updated by t, s will see the change as well. This ends my FYI on pass by reference; try not to get caught up by this common error :)


next up previous
Next: A few notes about Up: General notes on Java Previous: IDEs
MM Hugue 2019-05-28