The actual implementation of how strings are managed are not supposed to be consequential in Java, except for the guarantees that:
- String x = "hi"; String y = "hi"; // guaranteed that x == y
- String x = "hi"; String y = new String("hi"); // no guarantees on == although likely !=
- String x = new String("hi"); String y = new String("hi"); // guarantee != but x.equals(y)
- String x = "hi"; String y = new String("hi").intern(); // guarantee x == y
Those are the rules for Strings....
In the past (and this will change with Java8), String.intern()
and String constants (String x = "hi"
) were allocated on the PermGen space in the memory model.
As a result, they had different GC mechanisms, and it was possible to run out of memory if you used String.intern()
even if you had lots of free heap space (PermGen is/was typically less than 128MB).
Strings allocated with new String(....)
are otherwise on the regular heap, and have standard GC mechanisms.
As for why you/we create new instances of Strings using new String ("...")
, I can only think of one place where it makes sense to do it that way only, and that is if someone wanted to use the resulting object as a synchronization lock. This can make sense when debugging things..... but not much sense. You have to use 'new' so that you don't inadvertantly use the same String object as some other code for synchronization.
In general Java coding practice, I have typically not seen people using new String ("....")
. The reality is that people, for the most part, simply use string concatenation operators, etc. But, that does not mean it is wrong to do new String(...)
When I have looked at the source code for String, I have found that the code relies heavily on String being immutable. So, for example, new String(new String("hi")); only creates one array of char, and it is shared in both String instances. (and the inner instance will be GC'd anyway).