Speaking of CharSequence, one sneaky and bizarre option would be to make String's implementation of CharSequence::subSequence work the old way. subSequence returns a CharSequence, not a String, so it is free to return some specialised object which specifically represents a substring rather than a first-class string. Rather like slices in go, which would win Java some trendiness points.
This would be a surprising bit of behaviour, which means it's probably a bad idea. However, it wouldn't break any current code, because it preserves current behaviour, and hopefully wouldn't break future code, because people could learn about the quirk. Also, i think subSequence tends to be used to create temporary objects as computational intermediaries, rather than new long-lived objects which escape to the heap, so it shouldn't lead to excessive packratting in the way the old-style substring did.
This would be a surprising bit of behaviour, which means it's probably a bad idea. However, it wouldn't break any current code, because it preserves current behaviour, and hopefully wouldn't break future code, because people could learn about the quirk. Also, i think subSequence tends to be used to create temporary objects as computational intermediaries, rather than new long-lived objects which escape to the heap, so it shouldn't lead to excessive packratting in the way the old-style substring did.