The thing I mind is that there is now no way to get the old behavior. String is a final class, so you cannot override it and add a field, even. You can roll your own - if there is no code you do not control that takes a string. (And if you don't mind having to write your own string class!)
And it being done in a "bugfix" release? That's unacceptable.
I agree - echoing the sentiments of another commentator here, I feel like one of the tenets of Java is backwards compatibility. While the change doesn't affect functionality, it can turn code that previously had a space complexity of O(1) into one that is O(n). This is probably a Bad Thing.
Conversely, for people new or somewhat-new to the language, the change probably makes sense from a principle of least surprise. From the start, you're taught that Strings are immutable objects, so you probably understand that `.substring()` produces a new instance object. Not having the original memory freed when you remove all references to the original string would likely be puzzling at first.
In this respect, the Java/Oracle folks likely decided that optimizing for the "parsing/tokenization" use case (where you make lots of substrings from a large original string and thus it makes sense to use the same underlying character array) was more novel and less frequent than the use case of "just pulling a small substring from a much larger one and then discarding the large one."
> You can roll your own - if there is no code you do not control that takes a string.
You can roll your own for the standard String too, through the bootstrap class loader.
Although I don't know how many assumptions about the internals of the string class are baked into the JVM. But I think you could replace substring() relatively safely.
Given the pain that would be associated with rolling your own, why not make the case that a new method be added to the String interface that provides the old behavior? Legacy applications still need to change, but it would be a relatively straight-forward mechanical replacment.
That requires storing an extra two fields per String (int length, offset;), which is costly. Users who need constant-time substrings can simply implement their own class `Subsequence extends CharSequence` with a constructor taking a CharSequence and two ints. Users who need to pass a substring to a foreign function which only accepts String do need to copy, but that's not a major enough use-case to justify upping the memory usage of most applications.
And it being done in a "bugfix" release? That's unacceptable.