Here's what happens when you code o.equals(p1)
:
When Java compiles this, it looks at the type of o
, and it sees that it is Object
, because that's what you declared it to be. It won't know that it's a Pop
. As far as the compiler is concerned, it could be an object of any type. (You can tell by looking at the previous code that it will be a Pop
, but the compiler doesn't do that kind of analysis.)
The Java compiler looks at the Object
class for a matching definition of equals
. There's only one definition of equals
, and it matches (that is, the argument list is compatible with the definition). So the Java bytecode is created to say, "We're calling the method equals
defined in Object
."
At run time, when the call is made, it calls the method equals
defined in Object
, like the bytecode says. Any time Java makes a call, though, it will use an overriding call if there is one. So it looks at the actual class, Pop
, and sees whether Pop
(or any other superclass between Object
and Pop
, but there isn't one here) overrides that method in Object
. The first method in Pop
does override it, so that's the one that's executed, and "O"
gets printed. The second equals
method isn't looked at at all, since it doesn't override the equals
in Object
.
I don't know what mechanism the compiler uses for storing override information. But in another compiler for a different language that I've worked with, methods get indexes, or "slot" numbers, in a vector. When Object
is defined, its methods get unique slots; the slot for equals
might be, say, 7. So the 7th entry in the vector would be the address of equals
. When Pop
is defined, since the first equals
overrides the one in Object
, it would also get slot 7. The second equals
doesn't override anything, so it gets a new slot number, maybe 18. So there would be a vector where index 7 contains the address of the first equals
in Pop
, and index 18 contains the address of the second one. Now, when the code calls equals
in Object
, the code says something like "call whatever method is in slot 7". For a Pop
object, the method in slot 7 will be the first equals
, which prints "O"
. But it never looks at slot 18. I doubt that Java operates exactly in this way, but the effect is similar. Basically, there's some ID that gets looked up, and the method for that ID is called; Java does not, at run time, search for another method defined in the class that might get called.
MORE: If you really want the behavior where it prints "P"
if its argument is a Pop
, you can do it like this:
@Override
public boolean equals(Object o){
if (o instanceof Pop) {
return equals((Pop)o);
// this equals will be the one below, because of overload resolution
}
System.out.print("O");
return false;
}