There are a number of questions tangled together here, let me try and tease them apart.
- How do arrays of value types work;
- Are there short-term plans to migrate String to be a value class, like we have for Integer;
- Are there long-term impediments to migrating String to be a value class.
Arrays will remain identity objects. (All objects will remain reference objects.) In the short term, this is a forced move because arrays in Java are mutable, and mutability requires identity. In the longer term, even if we had immutable arrays (which we would like to do, we call these "frozen" arrays), there is little value to stripping arrays of their identity, for several reasons, including the one you mention (there is limited value in trying to flatten arrays as they are generally large.)
Arrays of (references to) value objects are candidates for flattening in their layout, just as objects whose fields are (references to) value objects. (The model that all objects are referred to by references is unchanged; for references to value types we may be able to optimize away the physical representation of the reference (the pointer)).
In the short term, String is not on the list of classes that will be migrated to a value type. (Classes on that list include the primitive box classes like Integer and Long, date-time classes like LocalDate, and other utility classes like Optional, likely with more over time.)
Migrating String to a value class is more challenging for multiple reasons:
The identity of String may be significant to some code. The String::intern method has been present since day 1, and many frameworks rely on interning of strings. While this is theoretically not a problem (the effect would just be that more strings that are .equals() would also be considered ==, which mostly seems harmless), String is so pervasive that it is hard to imagine all the code that would be affected by such a change.
There may well be code out there that synchronizes on String instances. While we might say that this is silly, it has been valid Java code for 30 years, so such a change would not be behaviorally compatible. This might still be OK, but it would have to be done carefully over a longer term.
The current implementation of String uses mutable fields for caching the hash code, and mutability requires identity.
It would likely perturb the cost of == operations on String, which might conceivably show up as a macro change in performance (since Strings are so pervasive).
So, there are many reasons to tread carefully. But, could String ever be migrated? I believe so. Assuming that the nonfunctional impact (performance perturbations, equality becoming more liberal) were acceptable, the mutable state of the String used to cache the hash code (which is also the subject of a benign data race) could be moved into the backing character array instead. This would be an expensive implementation change (since there is so much code in the JVM to special-case String operations to make them fast), but would be possible, and might eventually be considered.
So, there is no "clinch" argument here that it will never happen, but there are surely impediments to overcome.
Finally, I would recommend that you get "stack allocation" out of your mental model of value classes; it is not a helpful mental model. It carries two incorrect assumptions: one, that all Java objects are allocated on the heap, which is simply not true, completely separate from Valhalla. And two, to the extent that the JVM can elide heap allocation, it is far more likely that it will be scalarized and the fields hoisted into registers, than allocated on the stack (though excess registers can spill to the stack as part of the method invocation protocol.)
Valhalla won't change this; it just increases the number of objects that the JVM can prove can be safely scalarized.