运行这部分代码时,为什么我会得到“O'而不是' P'?
class Pop{
@Override
public boolean equals(Object o){
System.out.print("O");
return false;
}
public boolean equals(Pop p){
System.out.print("P");
return false;
}
public static void main (String[] args)
{
Pop p1 = new Pop();
Object o = p1;
o.equals(p1);
}
}
答案 0 :(得分:3)
以下是代码o.equals(p1)
时发生的情况:
当Java编译它时,它会查看o
的类型,它会看到它是Object
,因为这就是你声明它的内容。它不会知道它是Pop
。就编译器而言,它可能是任何类型的对象。 (您可以通过查看以前的代码来判断它是Pop
,但编译器不会进行这种分析。)
Java编译器查看Object
类以查找equals
的匹配定义。 equals
只有一个定义,它匹配(即参数列表与定义兼容)。因此创建Java字节码时说:“我们正在调用equals
中定义的方法Object
。”
在运行时,进行调用时,它会调用equals
中定义的方法Object
,就像字节码所示。但是,只要有Java拨打电话,它就会使用覆盖的呼叫。因此,它会查看实际的类Pop
,并查看Pop
(或Object
和Pop
之间的任何其他超类,但此处没有一个超级类)覆盖Object
中的方法。 Pop
中的第一个方法会覆盖它,因此执行的方法会被打印出来"O"
。第二个equals
方法根本没有查看,因为它没有覆盖equals
中的Object
。
我不知道编译器用于存储覆盖信息的机制。但是在另一个我使用过的不同语言的编译器中,方法在向量中获取索引或“槽”号。定义Object
时,其方法获得唯一的插槽;例如,equals
的插槽可能是7.因此,向量中的第7个条目将是equals
的地址。定义Pop
后,由于第一个equals
会覆盖Object
中的equals
,它也会获得第7个插槽。第二个equals
不会覆盖任何内容,因此它会获得一个新的插槽号,可能是18.所以会有一个向量,其中索引7包含Pop
中第一个equals
的地址,索引18包含第二个的地址。现在,当代码在Object
中调用Pop
时,代码会显示“调用插槽7中的任何方法”。对于equals
对象,插槽7中的方法将是第一个"O"
,它会打印"P"
。但它从未看过第18行。我怀疑Java是否以这种方式运行,但效果类似。基本上,有一些ID被查找,并且调用该ID的方法; Java在运行时不会搜索可能被调用的类中定义的另一个方法。
更多信息:如果你真的想要打印Pop
的行为,如果它的参数是 @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;
}
,你可以这样做:
target