14

Beginner java question, but I cannot understand how call-by-Value ( or Reference ) is working in the example below -

How come the String value is not modified after it exits the method while my custom String Object is. ? Same with other classes like Date..

public class StringMadness {

public static void main(String[] args) {
    String s = "Native String";
    CustomStringObject cs = new CustomStringObject();
    System.out.println("Custom String Before: " + cs.str);
    hello(cs);
    System.out.println("Custom String After: " + cs.str);

    System.out.println("Native String Before: " + s);
    hello(s);
    System.out.println("Native String After: " + s);
}

private static void hello(String t) {
    t = "hello " + t;
}

private static void hello(CustomStringObject o) {
    o.str = "hello " + o.str;
  }
}

class CustomStringObject {

String str = "Custom String";
}
Anand Hemmige
  • 3,083
  • 5
  • 18
  • 31

5 Answers5

25

Compare these two methods:

private static void hello(String t) {
    t = "hello " + t;
}

private static void hello(CustomStringObject o) {
    o.str = "hello " + o.str;
}

In the first case, you're assigning a new value to t. That will have no effect on the calling code - you're just changing the value of a parameter, and all arguments are passed by value in Java.

In the second case, you're assigning a new value to o.str. That's changing the value of a field within the object that the value of o refers to. The caller will see that change, because the caller still has a reference to that object.

In short: Java always uses pass by value, but you need to remember that for classes, the value of a variable (or indeed any other expression) is a reference, not an object. You don't need to use parameter passing to see this:

Foo foo1 = new Foo();
Foo foo2 = foo1;
foo1.someField = "changed";
System.out.println(foo2.someField) // "changed"

The second line here copies the value of foo1 into foo2 - the two variables refer to the same object, so it doesn't matter which variable you use to access it.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • Ahh.. I see it. thanks.... Originally, my `hello(CustomStringObject o )` was instantiating a new instance as in `o = new CustomStringObject()` and I noticed outside of hello method, the instanation never had any effect. This is what triggered the question. – Anand Hemmige Aug 03 '12 at 19:04
  • @Jon Nice explanation. The Foo example helps. +1 – Brian Mar 06 '14 at 04:52
  • If caller passes null reference then i have observed callee modification does not reflect to caller.why it is so ? – Nagappa L M Sep 29 '15 at 10:40
  • @feelgoodandprogramming: For exactly the same reason as if you change the parameter itself, that isn't visible to the caller. The reference is passed by value... – Jon Skeet Sep 29 '15 at 11:09
  • How does this work with a 'primitive' object like Boolean? If I pass a method this object and then set it outside the method, does that setting outside the method now apply inside the method? – Brian Reinhold Mar 29 '17 at 19:31
  • @BrianReinhold: All the wrapper types (`Boolean`, `Integer` etc) are immutable. – Jon Skeet Mar 29 '17 at 19:42
  • This -> "but you need to remember that for classes, the value of a variable is a reference" is what most other explanations tend to miss out on and is the basis of the MOST confusion on this point. But, @JonSkeet, you need to also mention it COPIES the reference and passes it, its not the orig ref. – killjoy Sep 30 '18 at 15:16
  • @killjoy: You mean like after the example: "The second line here **copies the value of `foo1` into `foo2`**"? I don't think I'd ever talk about "the orig ref" any more than I'd talk about "the original integer". – Jon Skeet Sep 30 '18 at 16:16
  • @JonSkeet Guess I missed that...you're good then :) – killjoy Oct 01 '18 at 17:46
  • to clarify even further, you can assign o to null then see the change is not visible ......private static void hello(CustomStringObject o) { o = null; } – Pete_ch Dec 14 '19 at 07:29
4

There's an important difference between the two methods: using hello(String) you're trying to change the reference to the String, and with hello(CustomObject), given a reference, you're using the reference to change a member of the object.

hello(String) takes a reference to a String. In the function you're trying to change which object that reference points to, but you're only changing the pass-by-value copy of the reference. So your changes aren't reflected outside the method.

hello(CustomObject) is given a copy of a reference to an object, which you can then use to change the actual object. Think of this as changing the contents of the object. So your changes are reflected in the caller.

Given a reference to an object, you can change the object using it's exposed methods/fields

pb2q
  • 54,061
  • 17
  • 135
  • 139
  • Also, note that Strings are immutable. When you call hello(String) a copy of the string address is passed (e.g: 0xABC4). In that function when you assign a new value to a string this will generate a new address for that string (e.g: 0xABC5) that will not be seen outside your function. – Adrian May 25 '20 at 06:32
0

t will point to new object and scoped to method only, so changes not visible outside.

Second case, the value you are changing will be updated to object,so those changes are visible after method call.

kosa
  • 63,683
  • 12
  • 118
  • 157
0

Because for the String you are just changing the local parameter reference.

kgautron
  • 7,171
  • 8
  • 35
  • 58
0

Doesn't work because String is an immutable object

Roberto
  • 3,510
  • 30
  • 26