覆盖equals()

时间:2016-12-18 06:11:43

标签: java override

运行这部分代码时,为什么我会得到“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);
        }
    }

1 个答案:

答案 0 :(得分:3)

以下是代码o.equals(p1)时发生的情况:

  1. 当Java编译它时,它会查看o的类型,它会看到它是Object,因为这就是你声明它的内容。它不会知道它是Pop。就编译器而言,它可能是任何类型的对象。 (您可以通过查看以前的代码来判断它是Pop,但编译器不会进行这种分析。)

  2. Java编译器查看Object类以查找equals的匹配定义。 equals只有一个定义,它匹配(即参数列表与定义兼容)。因此创建Java字节码时说:“我们正在调用equals中定义的方法Object。”

  3. 在运行时,进行调用时,它会调用equals中定义的方法Object,就像字节码所示。但是,只要有Java拨打电话,它就会使用覆盖的呼叫。因此,它会查看实际的类Pop,并查看Pop(或ObjectPop之间的任何其他超类,但此处没有一个超级类)覆盖Object中的方法。 Pop中的第一个方法会覆盖它,因此执行的方法会被打印出来"O"。第二个equals方法根本没有查看,因为它没有覆盖equals中的Object

  4. 我不知道编译器用于存储覆盖信息的机制。但是在另一个我使用过的不同语言的编译器中,方法在向量中获取索引或“槽”号。定义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