This question already has answers here:
What is meant by immutable?
(17 answers)
Closed 9 years ago.
I'm trying to understand exactly how Java strings are immutable. I get that this should probably be an easy concept, but after reading several online web pages I still don't quite understand.
I don't understand how Java Strings are "immutable". I currently have the following code:
public static void main(String[] args) {
String name = "Jacob Perkins";
System.out.println( name );
name = name + "!";
System.out.println( name );
}
My output is the following:
Jacob Perkins
Jacob Perkins!
Why is this happening if a string is supposed to be immutable? Why am I able to re-assign a value to the string?
Let an image explain this for you:
On the left side, you have the variable, which in fact is a reference.
String name = "Jacob Perkins;" The String "Jacob Perkins" is created, and name points to it.
name = name + "!"; A new String "Jakob Perkins!" is created, and the reference now points to the new String. The old one, however, remains unchanged, because String is immutable.
The string itself, once created, can never be changed. What your code sample does is to replace the string in name with a new string that was constructed from the previous contents of name, and an exclamation point. (The original contents of name, which are no longer referenced by any variable, will eventually be reaped by the garbage collector.)
If you were to examine the compiled code (or step through it with a debugger), you would discover that your name + "!" expression had been compiled into the creation of a StringBuilder object and a few operations on that object.
That is, the strings are immutable, but the variable name is not. Its value changes, to point to different strings. The strings themselves never change.
The String objects are immutable only the variable reference changes.
In your example the "Jacob Perkins" object still exists and a new object "Jacob Perkins!" gets created.
The name variable points to the new object.
Maybe this will help you to understand.
Let's say you have a class Point (java.awt.Point).
Let's say you have one instance p:
Point p = new Point(0,0);
Then you make create a new variable y referencing the same object p as:
Point y = p;
If you change the value of p, you also change y. Because the class Point is mutable.
p.setLocation(1,1);
It makes y reference the location 1,1 as well.
Using the String class it does not happen.
String a = "123";
String b = a;
If you make a = a + "4";
The new value of a will be "1234" but b is still "123";
The object they were referencing didn't change, it's just that a is pointing to another object now.
What actually happens is there are 3 String objects created. "Jacob Perkins", "!" and "Jacob Perkins!". You didn't really modify the "Jacob Perkins" instance. You just changed the reference of the name variable, from "Jacob Perkins" instance to "Jacob Perkins!".
String name = "Jacob Perkins";
String name2 = name + "!";
name.substring(5); // or wather syntax is
Those do not change variable name
In Java there are references and there are values.
When you say
String foo = "John Smith";
foo is a variable, holding a reference. The reference points to the object, or value, containing "John Smith".
The reference held by the variable is mutable. I can do this:
foo = "Jack Smith";
And I have mutated the reference. However if I write code like this:
String foo = "John Smith";
String bar = foo; //bar's reference is a copy of foo's reference - the same value
foo = "Jack Smith";
System.out.println(bar); //prints John Smith
We see that even though we changed foo, bar has not changed. Why? Simply, when we wrote foo = "Jack Smith"; we made foo point to a new String. We didn't reach through foo and modify the string, since No method in Java mutates, or can mutate a String. Instead, a new String is returned, and the variable is made to point to the new, also immutable String. This way, the object a String variable 'points' to can never be modified by anything but through that variable. This is an important property of the Java language that it guarantees.
Related
I have a question about String's immutability, namely, in the first situation the variable name does not change.
String name = "Unknown" ;
name.concat("Boy");
System.out.println (name);
But in the second case, the variable changes its value.
String name = "Unknown" ;
System.out.println (name);
name = "Test";
System.out.println(name);
Why the variable does not change in the first case, but in the second case as much as possible?
Strings are immutable - they do not change.
The name variable is pointing to the string "Unknown"
If you look at the docs for String found here,
you will see that concat() returns a String which is the brand new String that concatenates "Unknown" with "Boy".
The name variable is still pointing to the "Unknown" string.
In order for name to change you need to reassign it to the String returned by concat:
name = name.concat("Boy");
In the second example you're reassigning the reference to "Test".
None of the strings changed, just the references.
Thats how string concatnation works. It doesnt concat to your existing string, but creates a new one.
String name = "Unknown" ;
name.concat("Boy");
This creates and returns a new string "UnknownBoy" which you don't store.
Refer to the String API for how the method behaves. https://docs.oracle.com/javase/9/docs/api/java/lang/String.html#concat-java.lang.String-
It looks you are confused between the reference variable and Object, in your case name is a reference variable of type String which can hold the reference to a String object. Please go through this for the understanding of reference, variable and object.
In your first case, name is a variable which holds the reference to the String Object "Unkown" and when name.concat("Boy") a new String object ("UnkownBoy") will be created but name variable still holds the reference to the old object ("Unkown") because you did not update the reference anywhere in the first case.
In your second case you have updated the reference variable by name = "Test"; , that means now name will hold the reference of a new String Object "Test".
From my understanding of Java, String is immutable. So the following will not concatenate and only give me the output app, proving it is immutable. I get that.
String apple = new String("app");
apple.concat("le");
System.out.println(apple);
But I am able to change the value of the String after initializing it with some value. Isn't this considered immutable anyway?
String orange = "ora";
orange = "orange";
System.out.println(orange);
The Object is immutable, the reference is not. You can change the reference as often as you like with orange = "Orange" but you are not changing the object. You are merely letting go of the old one and attaching the reference to the new one.
When you do:
orange = "orange";
what happens behind the scenes is:
orange = new String("orange");
That is, orange, as a reference to a String, is modified. It just points to a different String instance.
In this statement:
apple.concat("le");
what happens is that you create a new String object which is the result of apple.concat(new String("le")), but you don't assign it...
But then again you are dealing with strings here; strings are one of the few classes in Java which have built-in behaviors, such as:
final String x = "a" + "b";
which in fact translates to:
final String x = new StringBuilder("a").append("b").toString();
You have stepped into a hornet's nest.
Instances of the String class are immutable. The apple variable is not immutable, but it would be if you declared it final.
For example, the following code is mutating the object:
Person p = new Person("John");
p.setName("Jenny"); // <-- mutating
Immutable objects (like String, Integer, ...) have no method that change the state of the object.
In contrast, the following code is changing the value of p, but is not mutating any objects:
Person p = new Person("John");
p = new Person("Jenny");
p is simply updated to reference a different Person object. The original "John" object still exists (until garbage collected).
Now, if p was defined as final, then it (the variable) would be immutable too:
final Person p = new Person("John");
// Cannot: p = new Person("Jenny");
In your particular case, concat does not mutate the String, it creates a new string and returns it, so you need to:
String apple = new String("app");
apple = apple.concat("le");
System.out.println(apple); // prints "apple"
Here the variable is updated, but not the String object.
According to Wikipedia, an immutable object is:
an object whose state cannot be modified after it is created.
However, you are not modifying the original orange String object ("ora"): you are creating a new String object ("orange"), and this new object is being assigned to a variable.
Easy as cake
If that doesn't make sense, think of it this way. Supposing some Object was a block of chocolate cake, you can add icing or cut out parts of this cake without actually changing the identity of the cake. However, if you wanted to change it to a red velvet cake, you have to make a new cake, because you cannot modify a chocolate cake to make it into a red velvet cake (for practical purposes) the original. An immutable object means you cannot cut, or ice... that "cake", but you can replace it with a new cake.
orange = "orange" only means that orange is pointing to a new String instance instead of the old one ("ora").
Immutability means that you cannot change an object's state once it has been created. You haven't changed the state of the string instance that orange is referring to; you just made it refer to a new instance. Changing an object's state requires you to either call a method on that object that changes its state, or modify one of its publicly-accessible properties.
You're also confusing immutability of objects with immutability of references. To make a reference immutable (i.e., make sure you cannot make it point to something else once it has been initialized) you use the final keyword.
So if you had:
final String orange = "ora";
orange = "orange";
You would now get an error because the reference is immutable and cannot be reassigned.
The Object is immutable while the reference is not. You can change the reference but not object.
Adding an example to make us more clear
String orange1 = "ora";
String orange2 = orange1;
System.out.println("orange1: " + orange1 + " , orange2: " + orange2);
System.out.println("----------------------");
orange2 = "orange";
System.out.println("orange1: " + orange1 + " , orange2: " + orange2);
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 6 years ago.
I have below two situations related to ArrayList get method, one with custom class and one with String class:
1. Below is the example of modifying Custom class ArrayList element:
ArrayList<MyClass> mTmpArray1 = new ArrayList<MyClass>();
MyClass myObj1 = new MyClass(10);
mTmpArray1.add(myObj1);
MyClass myObj2 = mTmpArray1.get(0);
myObj2.myInt = 20;
MyClass myObj3 = mTmpArray1.get(0);
Log.d(TAG, "Int Value:"+myObj3.myInt); // Prints "20"
2. And below is the example of modifying String ArrayList element:
ArrayList<String> mTmpArray2 = new ArrayList<String>();
mTmpArray2.add("Test_10");
String myStr1 = mTmpArray2.get(0);
myStr1 = "Test_20";
String myStr2 = mTmpArray2.get(0);
Log.d(TAG, "Str Value:"+myStr2); // Prints "Test_10"
So in case of MyClass ArrayList, when I call get and modify the value, then I see change is reflecting when I do get again.
But same way when I modify String ArrayList, then changes are not reflecting.
What is the different in of the get method in both the scenarios?
Is it that in case of String, String class creating deep copy and returns new object, and in case of Custom class shallow copy is created?
In the first scenario applicable to "LinkedHashMap", "HashMap" and "List"?
Your are not doing the same thing in the two cases.
Here you update the state of an object, so the change affects the object stored in the list :
myObj2.myInt = 20;
Here you are assigning a new object to a local variable, so the list is not affected :
myStr1 = "Test_20";
If String was mutable, you could have modified the String by calling some method, and the change would have been reflected in the object stored in the list :
myStr1.setSomething(...);
On the other hand, if in the first case you would have changed the value of the local variable, the object stored in the list wouldn't have been affected :
myObj2 = new MyClass (...);
Strings are immutable. You're not inserting the new string into the array list.
When you do String myStr2 = mTmpArray2.get(0);, even tho you are pointing to a reference in the ArrayList, any attempt to change the value, will (because of String immutability) create a new String (myStr2) that will not reference the ArrayList anymore.
When you do myStr1 = "xxx", you're not actually changing the ArrayList reference, you're changing a new (copy) (now called myStr1) that was grabbed from the ArrayList and it has a local scope.
Read some more about Strings: Immutability of Strings in Java
Now in the first example, you are pointing to a mutable object (your custom class) so you're literally changing the direct value, through the reference. Welcome to Java. ;)
Unrelated: This code: MyClass myObj1 = new MyClass(10); is (arguably) considered bad. It's better to use a factory pattern that is a lot easier to read. In other words, public constructors with parameters are hard to read (for example, I have no idea what I am constructing when I read your code).
A (perhaps) better approach would be: MyClass myObj = MyClass.createInstanceWithCapacity(10); // i've invented the name because I don't know what your 10 is, but look at both, which one do you think is easier to understand upon first glance?
Disclaimer: The above unrelated comment is my personal opinion and not all developers will agree. ;)
Strings have very nice property called "Immutablity"
This means that String cannot be mutable (changed), when we create/
try to refer to old string, a new instance string is created. And any
changes we do are saved in new instance and it do not affect the old
string
For example,
String s = "Old String";
System.out.println("Old String : "+s); // output : Old String
String s2 = s;
s2 = s2.concat(" made New");
System.out.println("New String : "+s2); // output : Old String made New
System.out.println("Old String is not changed : "+s); // output : Old String
These is no difference between the two "get" calls. The difference is between the types that the ArrayList is holding, and what you're doing the references the "get" method returns.
In your first example, you do this:
MyClass myObj2 = mTmpArray1.get(0);
myObj2.myInt = 20;
Here, you're getting a reference to the MyClass instance in the ArrayList in position 0, and you are modifying a field within this instance.
In your second example, you do this:
String myStr1 = mTmpArray2.get(0);
myStr1 = "Test_20";
Here, you're getting a reference to the String instance in the array list, and then you're giving myStr1 a reference to a different string which you create ("Test_20"). It's as if you did wrote myObj2 = new MyClass(20); in the 2nd line in the 1st example.
So, in short, in the 1st example, you access a field within the object by altering it from the reference you grabbed. In the 2nd example, you simply altered your reference to point at a different String.
I should also mention that in Java, Strings are immutable, meaning once they have been created, they cannot be changed.
String is an immutable class. A line like
myStr1 = "Test_20";
does not change the value of the String object myStr1 is pointing to. Instead a new String is created and myStr1 is modified to point to the new String. The original String is unchanged and can be retrieved from the ArrayList.
Your MyClass object is clearly mutable. Only one instance is created and its state is changed by the assignment
myObj2.myInt = 20;
Hence when this object is retrieved from the ArrayList, its new state is seen.
You simply do NOT change the list in your 2nd example.
In the first example, you are doing this:
Get the first object from the list and store it in the variable called 'myObj2'
Modify the object stored in variable 'myObj2' by setting the int value of this object
But your second example is completely different:
String myStr1 = mTmpArray2.get(0);
myStr1 = "Test_20";
Let me translate that:
Get the first element from the list and store it in the variable called 'myStr1'.
Set the value of the variable 'myStr1' to "Test_20"
So, in case one you are modifying a variable of the object stored in the list. In case two you are retrieving the object stored in the list - and then re-use the variable you stored that retrieved object in and use it for something new - but that does not change the original list, of course.
To modify your list for a type like string, you would need to use set(x, "Test_20").
My textbook says a String is not over-writable or immutable, i.e, once you enter the value of a String you can't change it. But today when I was running the following code, the String str gets muted as the compiler does not give any error and the new String a's value is successfully entered into str.
class Test
{
static void main()
{
String str = "something";
String a ="anything";
str = a; //str is being over written without any error
System.out.println(str);
}
}
The output is : anything
So, is my book wrong ?
If my book is not wrong please give an example to show that Strings are immutable
The book is correct. When you say str = a you are not changing anything about the String 'something'. You should distinguish between str and something, they are not the same. "something" here is a String object in memory, whereas str is just the reference to that string. Same with the reference a.
When you say:
str = a
You are not changing something, you are in fact saying, "change the reference str to point to whatever the reference a is pointing to." The Strings remain the same, the references change.
On a similar note, this is why you may see in your book that concatenating Strings is expensive, as doing something like:
str = str + a
Would again not be changing the existing Strings, but instead creating a new String object which is equal to the concatenation of the String that the reference str is referring to and the String that the reference a is referring to.
You need to understand what immutable means. In your scenario you are just changing references.
str = a;
will make both a and str to point to String "anything". The Text Book is correct. String is immutable and can not be overwritten. If you check the JavaDoc for String. Most of the methods return a String. This is because any operation in a String will not change that String object but will result in a new String being created. Effectively you can never change a String after you create it. By Change I mean append new characters, remove characters without a new String object being created.
As many answers already point out is that you only change references. Immutable means you cannot change the string itself. for example you do:
String a = "anything";
System.out.println(a); // -> anything
a.substring(3);
System.out.println(a); // -> anything : this is because the String itself is
// immutable.
a = a.substring(3);
System.out.println(a); // -> thing : this is what immutable means to edit a string
// you must reassign it or assign it
// to a new variable
You're changing the reference of str to a. So str effectively becomes a's value.
they are just pointer to that string. so when you do str =a , you just assign pointer of a to str.
The contents of the String object is not being changed. What's happening is that a new String object is being assigned to the variable. The old String object still exists in memory but you just can't refer to it any more. The 'str' variable now refers to the String object containing "anything" but the String containing "something" still exists as it did before. Try assigning 'str' to another variable first and then, after assigning 'a' to 'str', check that other variable and you'll see that it still says "something", proving that that String was not overwritten.
In Java, the value of a variable is never an object, but a reference. Relevant to your case, the type String on the a variable says the variable is allowed to contain only references to String objects.
You can update the value in the variable, sure; but that won't touch the object it is referring to.
Strings are constant; their values cannot be changed after they are created.
The String object is created and stored on constant pool or literal pool.
In your case, when you say,
String str="something"; // An object is created on constant pool with value 'something' and reference 'str' is pointing to it.
String a="anything"; // An object is created on constant pool with value 'anything' and reference 'a' is pointing to it.
And when you do, str=a; then 'str' actually start pointed to 'a', but the object with value as 'something' remains on constant pool with the same value.
I have a question concerning establishing String objects in Java.
Let's say I create a String object like this:
String mystring=new String();
Now, if I take this String object and assign to it a string like this:
mystring="abc";
What exactly happened here? Is mystring addressed exactly to the original object or is it a different object? Like String mystring; is the short-hand for String mystring=new String(); what could mystring="abc"; stand for?
String mystring = new String();
creates a new String object and assigns the value of its reference to the variable mystring.
So
Variable Heap
-------- ----
mytring ---------------------> "" // an empty String object
Then you do
mystring="abc";
This assigns the value of the reference to the String object "abc" to the variable mystring. So
Variable Heap
-------- ----
mystring -------------------> "abc"
"" // will be garbage collected at some point
A variable does not change. The object it's referencing or the reference itself can change.
Like String mystring; is the short-term for String mystring=new
String();
No String mystring; is a variable declaration. When that line is executed, the variable mystring is declared but not initialized.
On the other hand, String mystring = new String() both declares and initializes the variable mystring.
for what could mystring="abc"; stand for?
That is an assignment expression, assigning the value of the reference to the String object "abc" to the variable mystring.
It's also important to understand that Strings are immutable. Once you create a String object, you cannot change it. For example, in the following code
String name = "user3133542"; // cool
name = "some other value";
You are not changing the object that name is referencing, you are creating a new object and assigning its value to the variable name.
The String API does not provide any methods to change its value. We therefore call it immutable.
Consider going through the Java String tutorial.
Also, before you ask your next question, read this
How do I compare strings in Java?
You are changing mystring with mystring="abc"; It is not the exactly to the original object at all. The mystring is a variable not object.