Why does the following example seem to refute that strings are immutable objects in Java?

I am using the OpenJDK Java compiler under Ubuntu. I wanted to convert an array of characters to a string, and when it seemed to end up with mixed results, I tried to write my own toString method. In this process, I wrote a test program in which (due to fun) I tried to compile the following code.

 class toString{ public static void main(String[] args){ string = "abc"; string = string + "bcd"; System.out.println(string); } } 

Now I know that String objects in Java are immutable, and the code should actually have generated an error, but, to my surprise, it printed abcbcd on the console. Does this mean that String objects in Java are mutable or is there something wrong with the OpenJDK compiler implementation in this case?

+4
source share
9 answers

The difference between the links to the object and the object itself.

 String XXX = "xxx"; 

Means: Create a new variable and assign a reference to an instance of the String object that contains the letter string "xxx".

 XXX = XXX + "yyy"; 

Funds:

Get a reference to the object that we have in a variable named XXX. Create a new object of type String that contains the string literal "yyy". Add them together by executing the string + operator. This operation will create a new String object containing the string "xxxyyy". After that, we again put the link to the new object in the variable XXX.

The old reference object containing "xxx" is no longer used, but its contents have never changed.

An example is given as counting evidence:

 String a = "abc"; String b = "def"; String c = a; a = a + b; System.out.println(a); // will print "abcdef". System.out.println(b); // will print "def". System.out.println(c); // will print "abc". // Now we compare references, in java == operator compare references, not the content of objects. System.out.println(a == a); // Will print true System.out.println(a == c); // Will print false, objects are not the same! a = c; System.out.println(a == c); // Will print true, now a and b points on the same instance. 

An object instance is something "abstract" that lives in the memory part of your program. The control variable is a reference to this part of the memory. You can access objects only through variables (or return values).

One object may have more than one variable pointing to it.

A string is immutable, meaning that you cannot change the contents of this memory area used by the String object, but, of course, you can change and exchange references to it, as you prefer.

+2
source

The code you posted above does not actually mutate any lines, although it seems like it is. The reason is that this line does not mutate the line:

 string = string + "bcd"; 

Instead, it means:

  • Build a new line whose value is string + "bcd" .
  • Change which string string refers to to refer to this new string.

In other words, the particular string string objects themselves were not changed, but the references to those strings were indeed changed. Invariance in Java usually means that objects cannot be modified, not references to these objects.

An important detail that confuses many new Java programmers is that the above line is often written as

 string += "bcd"; 

which looks even stronger, as if it combines bcd at the end of the line and thereby mutates it, even if it is equivalent to the above code and therefore does not cause any changes to the actual string object again, it works by creating a new string object and changing to which the link belongs to the object.)

To see what is happening here, you are actually modifying the link, not the line to which it refers, you can try rewriting the code to make string final , which prevents you from changing which link object. If you do this, you will find that the code no longer compiles. For instance:

 class toString{ public static void main(String[] args){ final String string = "abc"; string = string + "bcd"; // Error: can't change string! System.out.println(string); } } 

One final note, another common reason for grief for new Java programmers when using string is that string has methods that seem to modify the string, but don't actually do it. For example, this code does not work correctly:

 String s = "HELLO, WORLD!"; s.toLowerCase(); // Legal but incorrect System.out.println(s); // Prints HELLO, WORLD! 

Here the call to s.toLowerCase() does not actually convert the characters of the string to lowercase, but instead creates a new string with the characters set to lowercase. If you then rewrite the code as

 String s = "HELLO, WORLD!"; s = s.toLowerCase(); // Legal and correct System.out.println(s); // Prints hello, world! 

Then the code will behave correctly. Again, the key detail here is that assigning s does not change any particular string object, but simply adjusts what the s object refers to.

Hope this helps!

+20
source

No, there is no error - you do not change the contents of any string object.

You change the value of a string variable, which is completely different. Look at this as two operations:

  • Creating a new line, the result of the expression string + "bcd"
  • Assigning a link to a new line back to the variable string

Highlight them explicitly:

 String string = "abc"; String other = string + "bcd"; // abc - neither the value of string nor the object contents have changed System.out.println(string); // This is *just* changing the value of the string variable. It not making // any changes to the data within any objects. string = other; 

It is very important to distinguish between variables and objects. The value of a variable is only a reference or primitive value. Changing the value of a variable does not change the contents of the object to which it previously referred.

+5
source

This does not refute. It will not actually compile since the string is not declared as a String object. But let's say you had in mind:

 class toString{ public static void main(String[] args){ String string = "abc"; string = string + "bcd"; System.out.println(string); } } 

See the + operator creates a new line, leaving "abc" in tact. The original "abc" still exists, but all you really did was create a new line "abcbcd" and overwrite the original link to "abc" when executed: string = string + "bcd". If you change this code to this, you will see what I mean:

 class toString { public static void main(String[] args ) { String originalString = "abc"; String newString = originalString + "bcd"; System.out.println( originalString ); // prints the original "abc"; System.out.println( newString ); // prints the new string "abcbcd"; } } 
+1
source

String objects immutable, you simply rearrange the String value in string + "bcd" in your sample code. You do not modify the existing String object, you create a new one and assign it to the old name.

0
source

string = string + "bcd" sets a new String instance for the String variable, not for changing this object

0
source

what it will do is that it will create a new object and replace the old one. if you want the variable string to look at the row builder.

0
source

The String variable itself has been changed.

The String "abc" object is immutable, as is the String "bcd" object and the result of concatenation "abcbcd" . This last result is assigned to a variable.

No string was mutated while executing this code.

0
source

The string is immutable ... your entire example shows that you can assign a new string reference to a variable.

If we compile the code and modify it a bit:

 class toString{ public static void main(String[] args){ String string = "abc"; System.out.println(string); string = string + "bcd"; System.out.println(string); } } 

You will see "abc" and then "abcbcd", which may make you think that the line has changed, but it does not.

When you execute line = / * independently * /, you rewrite what used to be in a variable called string with a new value.

If String had a method, for example setCharAt (int index, char value), it would be modified.

0
source

All Articles