In general, there is very good reason to want to be able to test if two object references point to the same object. I've had plenty of times that I've written
... populate values ...
... etc ...
I may or may not have an equals function in such cases. If I do, the equals function may compare the entire contents of both objects. Often it just compares some identifier. "A and B are references to the same object" and "A and B are two different objects with the same content" are, of course, two very different ideas.
It's probably true that for immutable objects, like Strings, this is less of an issue. With immutable objects, we tend to think of the object and the value as being the same thing. Well, when I say "we", I mean "I", at least.
Integer three=new Integer(3);
Integer triangle=new Integer(3);
if (three==triangle) ...
Of course that returns false, but I can see someone thinking it should be true.
But once you say that == compares reference handles and not contents for Objects in general, making a special case for Strings would be potentially confusing. As someone else on here said, what if you wanted to compare the handles of two String objects? Would there be some special function to do it only for Strings?
And what about ...
Object x=new String("foo");
Object y=new String("foo");
if (x==y) ...
Is that false because they are two different objects, or true because they are Strings whose contents are equal?
So yes, I understand how programmers get confused by this. I've done it myself, I mean write if myString == "foo" when I meant if myString.equals("foo"). But short of redesigning the meaning of the == operator for all objects, I don't see how to address it.