Java is so dynamic that it's impossible to prove a class will only be used in "value friendly" ways. When objects have no identity the meaning of `==` is different, and the compiler would have to do some kind of whole program analysis to find out if there is any way an instance of the class could ever be checked for equality.
That's hard when you have type erasure and polymorphism and runtime class loading. And even if they pulled it off it would blow up compile times and be programmer unfriendly because adding one line could deoptimize an important class defined in another package. So they decided to bite the bullet and add a way to statically opt in for faster but incompatible behavior.
This is really interesting. I've worked and lived alongside Java since, like, becoming extremely proficient in AS3/ECMA5(ish) and understanding the low-level quirks of that VM, but I never dealt in Java.
What's funny to me is that by your description, AS3 started almost as dynamic as the objective mess you're describing, and somewhat correctly headed down a path of compile-time type safety along its trajectory, which kind of gave good guardrails for those of us who had to switch to a wild west nonsense of JavaScript tempered with some hints from typescript.
I wasn't aware that you could `==` two objects in Java and that it would, like, deconstruct them somehow and see if their contents matched rather than just telling you whether they referenced the same object. I'm not even sure if that is what you're saying, because that's wild and insane and it's the whole reason for observable classes in other languages (which are sort of hackish). But after so many years of like, figuring out the quickest ways to diff similar objects, relying on the VM to do it would feel like never the best solution to any given problem, and more of a footgun than a feature...?