String is immutable. What exactly is the meaning?
Before proceeding further with the fuss of immutability, let's just take a look into the String
class and its functionality a little before coming to any conclusion.
This is how String
works:
String str = "knowledge";
This, as usual, creates a string containing "knowledge"
and assigns it a reference str
. Simple enough? Lets perform some more functions:
String s = str; // assigns a new reference to the same string "knowledge"
Lets see how the below statement works:
str = str.concat(" base");
This appends a string " base"
to str
. But wait, how is this possible, since String
objects are immutable? Well to your surprise, it is.
When the above statement is executed, the VM takes the value of String str
, i.e. "knowledge"
and appends " base"
, giving us the value "knowledge base"
. Now, since String
s are immutable, the VM can't assign this value to str
, so it creates a new String
object, gives it a value "knowledge base"
, and gives it a reference str
.
An important point to note here is that, while the String
object is immutable, its reference variable is not. So that's why, in the above example, the reference was made to refer to a newly formed String
object.
At this point in the example above, we have two String
objects: the first one we created with value "knowledge"
, pointed to by s
, and the second one "knowledge base"
, pointed to by str
. But, technically, we have three String
objects, the third one being the literal "base"
in the concat
statement.
Important Facts about String and Memory usage
What if we didn't have another reference s
to "knowledge"
? We would have lost that String
. However, it still would have existed, but would be considered lost due to having no references.
Look at one more example below
String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1); // Yes, s1 still refers to "java"
What's happening:
- The first line is pretty straightforward: create a new
String
"java"
and refers1
to it. - Next, the VM creates another new
String
"java rules"
, but nothing
refers to it. So, the secondString
is instantly lost. We can't reach
it.
The reference variable s1
still refers to the original String
"java"
.
Almost every method, applied to a String
object in order to modify it, creates new String
object. So, where do these String
objects go? Well, these exist in memory, and one of the key goals of any programming language is to make efficient use of memory.
As applications grow, it's very common for String
literals to occupy large area of memory, which can even cause redundancy. So, in order to make Java more efficient, the JVM sets aside a special area of memory called the "String constant pool".
When the compiler sees a String
literal, it looks for the String
in the pool. If a match is found, the reference to the new literal is directed to the existing String
and no new String
object is created. The existing String
simply has one more reference. Here comes the point of making String
objects immutable:
In the String
constant pool, a String
object is likely to have one or many references. If several references point to same String
without even knowing it, it would be bad if one of the references modified that String
value. That's why String
objects are immutable.
Well, now you could say, what if someone overrides the functionality of String
class? That's the reason that the String
class is marked final
so that nobody can override the behavior of its methods.
What is difference between mutable and immutable String in java
Case 1:
String str = "Good";
str = str + " Morning";
In the above code you create 3 String
Objects.
- "Good" it goes into the String Pool.
- " Morning" it goes into the String Pool as well.
- "Good Morning" created by concatenating "Good" and " Morning". This guy goes on the Heap.
Note: Strings are always immutable. There is no, such thing as a mutable String. str
is just a reference which eventually points to "Good Morning". You are actually, not working on 1
object. you have 3
distinct String
Objects.
Case 2:
StringBuffer str = new StringBuffer("Good");
str.append(" Morning");
StringBuffer
contains an array of characters. It is not same as a String
.
The above code adds characters to the existing array. Effectively, StringBuffer
is mutable, its String
representation isn't.
Is new String() immutable as well?
new String()
is an expression that produces a String
... and a String
is immutable, no matter how it is produced.
(Asking if new String()
is mutable or not is nonsensical. It is program code, not a value. But I take it that that is not what you really meant.)
If I create a string object as
String c = "";
is an empty entry created in the pool?
Yes; that is, an entry is created for the empty string. There is nothing special about an empty String
.
(To be pedantic, the pool entry for ""
gets created long before your code is executed. In fact, it is created when your code is loaded ... or possibly even earlier than that.)
So, I was wanted to know whether the new heap object is immutable as well, ...
Yes it is. But the immutability is a fundamental property of String objects. All String
objects.
You see, the String
API simply does not provide any methods for changing a String
. So (apart from some dangerous and foolish1 tricks using reflection), you can't mutate a String
.
and if so what was the purpose?.
The primary reason that Java String
is designed as an immutable class is simplicity. It makes it easier to write correct programs, and read / reason about other people's code if the core string class provides an immutable interface.
An important second reason is that the immutability of String
has fundamental implications for the Java security model. But I don't think this was a driver in the original language design ... in Java 1.0 and earlier.
Going by the answer, I gather that other references to the same variable is one of the reasons. Please let me know if I am right in understanding this.
No. It is more fundamental than that. Simply, all String
objects are immutable. There is no complicated special case reasoning required to understand this. It just >>is<<.
For the record, if you want a mutable "string-like" object in Java, you can use StringBuilder
or StringBuffer
. But these are different types to String.
1 - The reason these tricks are (IMO) dangerous and foolish is that they affect the values of strings that are potentially shared by other parts of your application via the string pool. This can cause chaos ... in ways that the next guy maintaining your code has little chance of tracking down.
Immutability of Strings in Java
str
is not an object, it's a reference to an object. "Hello"
and "Help!"
are two distinct String
objects. Thus, str
points to a string. You can change what it points to, but not that which it points at.
Take this code, for example:
String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"
Now, there is nothing1 we could do to s1
that would affect the value of s2
. They refer to the same object - the string "Hello"
- but that object is immutable and thus cannot be altered.
If we do something like this:
s1 = "Help!";
System.out.println(s2); // still prints "Hello"
Here we see the difference between mutating an object, and changing a reference. s2
still points to the same object as we initially set s1
to point to. Setting s1
to "Help!"
only changes the reference, while the String
object it originally referred to remains unchanged.
If strings were mutable, we could do something like this:
String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"
Edit to respond to OP's edit:
If you look at the source code for String.replace(char,char) (also available in src.zip in your JDK installation directory -- a pro tip is to look there whenever you wonder how something really works) you can see that what it does is the following:
- If there is one or more occurrences of
oldChar
in the current string, make a copy of the current string where all occurrences ofoldChar
are replaced withnewChar
. - If the
oldChar
is not present in the current string, return the current string.
So yes, "Mississippi".replace('i', '!')
creates a new String
object. Again, the following holds:
String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects
Your homework for now is to see what the above code does if you change s1 = s1.replace('i', '!');
to s1 = s1.replace('Q', '!');
:)
1 Actually, it is possible to mutate strings (and other immutable objects). It requires reflection and is very, very dangerous and should never ever be used unless you're actually interested in destroying the program.
How is String in Java an immutable object, but I can still change its value after creating one?
Your not changing its value you are creating a new String
. Technically your variable changes its value (memory location its pointing to)
to reference a new String
object but it is pointing to the new String
object not the same String
object.
You aren't actually changing the value of the original String
object you are just referencing a new String
so while the value of your variable does change you aren't actually changing the original String
object...Hope that makes sense.
What is meant by immutable?
Immutable means that once the constructor for an object has completed execution that instance can't be altered.
This is useful as it means you can pass references to the object around, without worrying that someone else is going to change its contents. Especially when dealing with concurrency, there are no locking issues with objects that never change
e.g.
class Foo
{
private final String myvar;
public Foo(final String initialValue)
{
this.myvar = initialValue;
}
public String getValue()
{
return this.myvar;
}
}
Foo
doesn't have to worry that the caller to getValue()
might change the text in the string.
If you imagine a similar class to Foo
, but with a StringBuilder
rather than a String
as a member, you can see that a caller to getValue()
would be able to alter the StringBuilder
attribute of a Foo
instance.
Also beware of the different kinds of immutability you might find: Eric Lippert wrote a blog article about this. Basically you can have objects whose interface is immutable but behind the scenes actual mutables private state (and therefore can't be shared safely between threads).
Related Topics
How to Make an Executable Jar File
How to Convert Jsonstring to Jsonobject in Java
Adding External Library to Artifact Jar in Intellij Idea
Java Hashmap: How to Get Key from Value
How Does the "Final" Keyword in Java Work (I Can Still Modify an Object.)
Swing: Link Toggle Buttons Together With a Button Group, Along With Corresponding Menu Items
Simpledateformat Ignoring Month When Parsing
Convert String to Double in Java
Causes of Getting a Java.Lang.Verifyerror
Resolving Dependency Problems in Apache Spark
How to Force Garbage Collection in Java
Difference Between Hashmap, Linkedhashmap and Treemap
Implementing Back/Forward Buttons in Swing
How to Pretty Print Xml from Java