There is nothing stopping a Java-like language from having statically-enforced immutable arrays. These would be of a different type to the existing mutable arrays. Freshly-constructed array literals can trivially be treated as immutable array constructors of this type, and the compiler will know which references have that type so that no mutation operations will be permitted, and no casts to anything but another immutable array type can be performed.
On this level, there’s no issue with using the existing static type system to back that. Java specifically does make its primitive arrays visibly special via their interactions with overloading, variadic methods, and erasure, and a new array type would be incompatible with those, but this isn’t a broader issue.
The more you’re happy to prohibit statically, the easier this is, and the more you can reuse the baseline primitive mutable arrays and implement the semantics purely in the compiler. Prohibiting all cast and assignment operations, and making the immutable type unassignable to mutable array types, is sufficient. If you want to hold them in erased generic storage locations, for example, you need to implement a distinct runtime type as well, but if you disallow that you can probably get away without it.
Your proposal that
a mutable array reference could be converted to an immutable one but not vice versa
works only for unique linear or affine array references; otherwise, it would still be possible to mutate the array via a pre-existing reference, just not through the new one. Unique references would be an additional new concept for Java, though a number of research languages that are broadly Java-like have general linear, affine, immutable, or read-only references already, and would get all this for free.
If only source-level literal immutable arrays are required, you don’t need this conversion at all. A method on the mutable array type that produces a new immutable array with the same contents covers many uses for it also.
A read-only array type, which could contain either a mutable or immutable array, would likely be useful. This would be a purely static construct, with no difference in the storage type, and it’s possible that this is more what you’re thinking of given the example. You couldn’t mutate an array through one of these references, but you could observe changes made through aliases.
It’s also worth noting that C#, perhaps the most Java-like language, has immutable “arrays” in the System.Collections.Immutable.ImmutableArray<T> struct. These have some runtime support and are accessed identically once created, but are not quite as primitive as base arrays and don’t have their compiler support.