Strings are immutable. String references are not. That's the distinction.
So:
String str = "abc";
str
is a variable, referring to an immutable string "abc". Now if I do:
str = "def";
str
is still a variable, referring to a different immutable string ("def"). I can change what str
points to all I want, str
is a variable. I can't change the actual content of any string (because Java's strings are immutable, by design). Whenever you do something that would seem to modify the string (say, toUpperCase
), what it's actually doing is creating a new string with a copy of the old string's contents, modified in the way described.
The point of having strings be immutable is that I know that if I have a reference to a string, that string can never change. This is a very useful guarantee when passing strings around. If we didn't have this guarantee, we'd be copying strings all the time just to protect ourselves from someone modifying them. For instance, consider a standard setter function for a name
property:
void setName(String n) {
this.name = n;
}
If strings weren't immutable, we'd have to do this:
void setName(String n) {
this.name = new String(n); // Blech, duplication
}
...so that we know our copy of the string won't change in ways we don't expect it to. This would result in a lot of duplication of string data in memory, most of it unnecessary, and so the designers of Java quite intelligently decided that strings would be immutable, and any changes you might want would create a new string rather than modifying the old one in-place. (You can get modify-in-place behavior for those situations that really warrant it by using char[]
instead.)
Regarding your separate question about the difference between str = "abc";
and str = new String("abc")
, the difference is that the latter (using the constructor) is guaranteed to return a new reference, whereas the former is not. E.g.:
String a = "abc";
String b = "abc";
String c = new String("abc");
a == b
(checking whether the references match, not the strings) will be true, because literal strings are interned. a == c
is guaranteed to be false, because we used the constructor for c
. a.equals(b)
and a.equals(c)
will both be true, because a
, b
, and c
all refer to equivalent strings.