0

I am confused why in the first code (Code 1), the object pointed to by myCounter was updated to the value 2 after passing to the method "print". But in the second code (Code 2), the object pointed to by str is still the same literal "This is a string literal." I thought the str (the str is an object reference just like myCounter I think) experience the same mechanism since it is also passed to a method, so shouldn't it get updated just like myCounter?

This is code 1:

public class PrimitiveVsReference{

private static class Counter {
    private int count;

    public void advance(int number) {
        count += number;
    }

    public int getCount() {
        return count;
    }
}

public static void main(String args[]) {        
    int i = 30;
    System.out.println("value of i before passing to method : " + i);
    print(30);
    System.out.println("value of i after passing to method : " + i);
    
    Counter myCounter = new Counter();
    System.out.println("counter before passing to method : " + myCounter.getCount());// this gives 0
    print(myCounter); 
    System.out.println("counter after passing to method : " + myCounter.getCount());// now this gives 2 after passing into the method "print"
}

/*
 * print given reference variable's value
 */
public static void print(Counter ctr) {
    ctr.advance(2);
}

/**
 * print given primitive value
 */
public static void print(int value) {
    value++;
}
}

Code 2:

String str = "This is a string literal.";

public static void tryString(String s)
{
    s = "a different string";
}

tryString(str); // isn't this here doing the samething as when myCounter is passed to print in Code 1?
System.out.println("str = " + str); // But this here output the original literal "This is a string literal."

Could someone explains what is going on?

john_w
  • 693
  • 1
  • 6
  • 25
  • This is the difference between modifying the content of an object (code 1) or creating a new object (code 2). – Mark Rotteveel Jul 11 '21 at 14:46
  • @MarkRotteveel So based on what you said, the second answer here by user16320675 (the explanations without getting any votes) is the correct reasoning. And the reasoning given by the first answer (the one with 2 upvotes) is not the correct answer (i.e. it has nothing to do with Immutable or mutable right?). Is it correct? As I want to understand the correct solution. – john_w Jul 11 '21 at 17:49
  • Yes, that's right. The fact string is immutable doesn't have to do with this (the same would happen if you had used `ctr = new Counter()` in `print` in code 1, and `Counter` is a mutable object). – Mark Rotteveel Jul 11 '21 at 17:55
  • @MarkRotteveel Oh thank you for pointing out the right solution. – john_w Jul 11 '21 at 17:57

2 Answers2

2

Since a string is immutable ("Once a String instance is created, the content of the String instance will never be changed"), that assignment creates a new string object that the copy of the reference now points to. The original reference still points to "This is a string literal."

You can try with StringBuffer or StringBuilder and see different results.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
VedantK
  • 9,728
  • 7
  • 66
  • 71
  • But how about myCounter, could you explain why myCounter is updated? – john_w Jul 10 '21 at 04:42
  • also could you explain what you mean by "that assignment creates a new string object"? which assignment is it? and also the meaning of "the copy of the reference now points to"? thank you – john_w Jul 10 '21 at 04:46
  • @user16320675 so it has nothing to do with the str being mutable or not? str is a String here. But if str is some other types say an object of type A, and we pass this object A to the method tryString(A str){ s = str;} (so assume tryString takes argument of type A), does that mean now s stores the address (i.e. the address in the heap memory) of the object str after the assignment s = str happening? Could someone explain more. So it has nothing to do with mutable or immutable? right? – john_w Jul 10 '21 at 18:59
  • @user16320675 So could you explain why in the second code, the str didn't get updated? but in the first code (code 1), the object myCounter get updated? – john_w Jul 10 '21 at 19:48
2

I'll try to show what I've meant in the comments using a StringBuilder - a mutable object - based on code posted in question.

Code 1

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder("abc");
    System.out.println("before passing to method: " + builder);
    method(builder);
    System.out.println("after passing to method: " + builder);
}

private static void method(StringBuilder bld) {
  bld.append("def");
}

should output:

before passing to method: abc
after passing to method: abcdef

there is only one instance of StringBuider in above code, the one being changed and displayed


Code 2

private static final StringBuilder ANOTHER_ONE = new StringBuilder("a different string");

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder("abc");
    System.out.println("before passing to method: " + builder);
    method(builder);
    System.out.println("after passing to method: " + builder);
}

private static void method(StringBuilder bld) {
  bld = ANOTHER_ONE;  // or bld = new StringBuilder("a different string")
}

should output:

before passing to method: abc
after passing to method: abc

there are two instances of StringBuider in above code; one being displayed, another being assigned in method


It can be seen that even if the object is mutable, an assignment to a parameter is not reflected in the variable used when the method is called. Actually it is an expression, resulting in a value, that is used to initialize the parameter of the method - in this specific examples, the expression happens to be just a single variable.

You can think of
s = "a different string"
being similar1 to
s = new String(new char[] {'a', ' ', 'd', 'i', 'f', 'f', 'e', 'r', 'e', 'n', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}).

1 - missing call to intern() so it is also interned as all literals (also harder to read and type)

user16320675
  • 135
  • 1
  • 3
  • 9
  • Oh thank you. I will try to understand your code as it will take sometimes for me to understand. But why would people upvote the first answer by Veke if the explanation there is not correct. – john_w Jul 11 '21 at 17:45
  • So I won't believe the real reason is "since the String is immutable". So that's not the correct reasoning. So I will take yours as the correct reasoning then. But just confused why people upvote the incorrect answer now. – john_w Jul 11 '21 at 17:46
  • and it makes me more confused. – john_w Jul 11 '21 at 17:46