The substring() method doesn't allocate a new character array for a String, but rather simply produces a String with a window onto the existing char array. This is an impementation of a flyweight pattern and was regarded as an optimisation.
So if I have a huge String (char array) and then create a substring, even if I garbage collect the original string, the original char array remains (despite the fact that you think you have a substring of, say, 2 chars). This problem is often encountered when (say) parsing a huge stream of input data (perhaps an XML file) and extracting a small amount of text via substring()
Using the seemingly redundant String(String str) constructor (a String constructor taking a String!) resolves this since it allocates a new (potentially smaller) char array, allowing the original to be garbage collected.
Note this behaviour has changed as of Java 7u6.