6

Hi Im studying for my scja exam and have a question about string passing by ref/value and how they are immutable. The following code outputs "abc abcfg".

What I want to know is why is this happening? Im not understanding what happens inside of method f. String is passed by value so surely it should change to "abcde" inside the method? Because if b+="fg" appends to the string why doesnt it work inside the method?

Thanks!

public class Test {

    public static void main(String[] args){
        String a =new String("abc");
        String b = a;
        f(b);
        b+="fg"
        System.out.println(a + " " + b);
    }

    public static void f(String b){
        b+="de";
        b=null;
    }
}
Taobitz
  • 546
  • 3
  • 10
  • 22

5 Answers5

8

The line b+="de"; in the void f(String b) functions creates a completely new object of String that does not affect the object in the main function.

So when we say String is immutable when mean any change on a String object will result in creating a completely new String object

public class Test {
    public static void main(String[] args){
        String a =new String("abc");

        String b = a; // both a & b points to the same memory address

        f(b); // has no effect

        // b still has the value of "abc"
        b+="fg" // a new String object that points to different location than "a"

        System.out.println(a + " " + b); // should print "abc abcfg" 
    }

 public static void f(String b){
    b+="de";  // creates a new object that does not affect "b" variable in main
    b=null;
 }
}
iTech
  • 18,192
  • 4
  • 57
  • 80
3

In your method f() you are assigning a new String to the parameter b, but parameters are just like local variables, so assigning something to them has no effect on anything outside the method. That's why the string you passed in is unchanged after the method call.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • so I would of had to do b = f(b) and return a string from method f? – Taobitz Feb 17 '13 at 00:02
  • Exactly! Even then, until you return the string, there's no effect outside the method. – Bohemian Feb 17 '13 at 00:05
  • It's also pointing out that if you were to do b = f(b) and return a String with your current coding, you would be left with the output "abc nullfg", as you say b = null. – Andrew Martin Feb 17 '13 at 00:08
  • I am pretty sure this is very incorrect. String is passed as value, the value is the pointer to the string. When you do anything b+="de"; or null, you effect the pointer. b+="de"; is the same as b = new String; If you do the same, but simply toss the string in a wrapper, and change the data in the wrapper, you will see the changes, as you changed the pointer that the data in the wrapper has, but not the wrapper itself. – StarWind0 May 16 '16 at 08:36
  • @StarWind Java ain't C. Java does not have the concept of pointers. The thing passed to the method is a reference to the String in the calling code - think of a reference as like the "address", which is assigned to the parameter, which is in turn a type of local variable in the method. When you assign something to that parameter/variable all that happens is that it now refers to a different object. Assigning something to a parameter has no effect whatsoever on variables or values outside the method. – Bohemian May 16 '16 at 17:26
  • @Bohemian Right. It does not have the concept of pointers. Now what is a pointer. A pointer is a reference to points to a memory location. Here we have a reference, with the distinction that the memory location is not of consequence as the JVM handles all of that. I think http://stackoverflow.com/questions/2629357/does-java-have-pointers sums it up better. What you did is overwrote the reference with a new one that will be collected by the garbage collector once it leaves the scope. What I have issue with, per my example, is that you state that "parameters are like local variables." – StarWind0 May 17 '16 at 04:03
  • The reference still effects the actual object is what I am getting at. Their mistake was not realizing that editing the string is really creating a new object. I want it to be clear that if one manipulates the data if the object ( which is blocked in string) that you will effect the object. That for example we have arrays.sort() which returns no value ( or any array manipulation). This might be what you did or tried to express but it did not read as such to me. – StarWind0 May 17 '16 at 04:07
  • 2
    @StarWind sure. If you *mutate* the object, then yes it's the *same* object being *changed* as the one assigned to the variable in the calling code, so changes are "seen" outside the method too. It's *assignment* that does nothing in the calling code. – Bohemian May 17 '16 at 05:56
3

This line of code:

b += "de";

Roughly translates to:

b = b + "de";

Which creates a new String and stores it in the local variable 'b'. The reference outside the method is not changed in anyway by this. There are a couple of key things to remember when trying to understand how/why this works this way.

  1. In Java, all method arguments are passed by value.
  2. Methods have a local stack where all their data is stored, including the method arguments.

When you assign a new object to a variable that was passed into a method, you are only replacing the address in the local stack, with the address of the new object created. The actual object address outside of the method remains the same.

Perception
  • 79,279
  • 19
  • 185
  • 195
0

When you pass the String into the method, it creates a new String object in the method. If you put a println statement in your method, like this:

public static void f(String b){
    b+="de";
    System.out.println(b);
    b=null;
}

You would see the output "abcde".

However, once you come out of the method, you go back to your original object, which has not been altered. Therefore, appending fg to it will only produce a NEW string (b), containing "abcfg".

Andrew Martin
  • 5,619
  • 10
  • 54
  • 92
0

Your creating a new object of String when you say something like b+="de"

Its like saying b = new String(b+"de");

If you really want to keep the value passed in then use a stringBuilder like this:

    StringBuilder a =new StringBuilder("abc");
        StringBuilder b = a;
        f(b);
        b.append("fg");
        System.out.println(a + " " + b);
    }

  public static void f(StringBuilder b){
        b.append("de");
        b=null;
    }

Now your output will be "abcdefg" because stringbuilder object b was passed into f as the value of the object itself. I modified the value without using "new" to point to another object. Hope its clear now.

j2emanue
  • 60,549
  • 65
  • 286
  • 456