5

I know that in Java, everything is passed by value. But for objects, it is the value of the reference to the object that is passed. This means that sometimes an object can get changed through a parameter, which is why, I guess, people say, Never modify parameters.

But in the following code, something different happens. s in changeIt() doesn't change when you get back to main():

public class TestClass {

    static String str = "Hello World";

    public static void changeIt( String s ) {
        s = "Good bye world";
    }

    public static void main( String[] args ) {
        changeIt( str );
        System.out.println( str );
    }
}

I'm guessing -- and I'd like confirmation -- that when you say s = "something" it's the same or equivalent to saying String s = new String("something"). Is this why s doesn't change? Is it assigned a whole new object locally which gets thrown away once you exit changeIt()?

Mat
  • 202,337
  • 40
  • 393
  • 406
ksnortum
  • 2,809
  • 4
  • 27
  • 36
  • 1
    I've seen this kind of question/answer before and I *still* feel like I need a review. +1 – BlackVegetable Jul 20 '12 at 19:40
  • It doesn't change because strings in Java are immutable objects. – anio Jul 20 '12 at 19:43
  • 1
    @anio No, that's not the reason this particular code doesn't change the string. It would be the same behavior for any object, immutable or not (since he's doing assignment, not invoking any method on the received object) – nos Jul 20 '12 at 19:47
  • Please note that this concept has nothing to do with String's being immutable! The reason is that object references are passed by value and methods have their own separate copy of the reference. – jn1kk Jul 20 '12 at 20:01

3 Answers3

4

that when you say s = "something" it's the same or equivalent to saying String s = new String("something")

Yes, pretty much. (though the JVM might do optimizations so that the same string literal used several times refers to the same String object).

Is this why s doesn't change? Is it assigned a whole new object locally which gets thrown away once you exit changeIt()

Yes. As you say, everything is passed by value in Java, even references to object. So the variable s in changeIt( String s ) is a different value from str you use in main(), it's just a local variable within the changeIt method. Setting that reference to reference another object does not affect the caller of changeIt.

Note that the String object s refer to is still the same String as str refers to when entering the changeIt() method before you assign a different object to s

There's another thing you need to be aware of, and that is that Strings are immutable. That means that no method you invoke on a string object will change that string. e.g. calling s.toLowerCase() within your changeIt() method will not affect the caller either. That's because the String.toLowerCase() does not alter the object, but rather returns a new String object.

nos
  • 223,662
  • 58
  • 417
  • 506
3

When you write

s = "Good bye world";

you are changing the value of s to be a reference to the new string. You are not changing the value of the string referenced by s.

Geoff Reedy
  • 34,891
  • 3
  • 56
  • 79
0

Yes, now 'S' points to brand new object whose scope is limited to that method. String may not be perfect example to understand pass-by-value concept. Instead of string, let us say pass some mutable object reference and make changes to that assign new object inside the method. You don't see them outside of the object.

public class MyMain {

    private static void testMyMethod(MyMain mtest) {
        mtest=new MyMain();
        mtest.x=50;
        System.out.println("Intest method"+mtest.x);
    }
     int x=10;
    public static void main(String... args)
    {
        MyMain mtest = new MyMain();
        testMyMethod(mtest);
        System.out.println("In main method: "+mtest.x);
    }
}

Read second answers in this SO discussion.

Community
  • 1
  • 1
kosa
  • 65,990
  • 13
  • 130
  • 167
  • This is wrong, you do see changes made to mutable objects: `static Point myPoint = new Point(0,0); public static void changeIt( Point p ) { p.setLocation(1,0); } public static void main(String[] args) { changeIt( myPoint ); System.out.println( myPoint ); }` Will print out `java.awt.Point[x=1,y=0]` – NominSim Jul 20 '12 at 19:48
  • @NominSim: Please check my example and when you made the parameter as final, then it is not possible to assign new object to that reference. – kosa Jul 20 '12 at 19:52
  • @NominSim: And if possible second answer in this link. http://stackoverflow.com/questions/40480/is-java-pass-by-reference – kosa Jul 20 '12 at 19:56
  • When you do `mtest=new MyMain();` you are changing `mtest` to reference a new `Object` the same thing that happens with String, so changing the new `Object`s `x` value does nothing. Remove that from your code and you will see the change persist, because it is a mutable `Object`. – NominSim Jul 20 '12 at 19:56
  • I know, my understanding about this question is about Pass-by-value. Not just about whether we can change the object state inside a method or not. – kosa Jul 20 '12 at 19:58
  • "...pass some mutable object and make changes to that object inside the method. You don't see them outside of the object." That was the issue that I had with your original, since making changes does persist outside the method. When you assign a new object you are no longer changing the original, which is why it does not change the outside object. I noticed you edited it to reflect assignment of a new object, removed my -1. – NominSim Jul 20 '12 at 20:04
  • @NominSim: Thanks! Its not just about -1. Initially I mis-understood this concept, but after reading above link couple of years agi it was clear. I want to make sure we are on same page. – kosa Jul 20 '12 at 20:06