Java 覆盖等于()

Java 覆盖等于(),java,overriding,Java,Overriding,当运行这部分代码时,为什么我得到的是“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");

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

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

  • 当Java编译它时,它会查看
    o
    的类型,并看到它是
    Object
    ,因为这就是您声明的类型。它不会知道这是一个
    Pop
    。就编译器而言,它可以是任何类型的对象。(通过查看前面的代码,您可以知道它将是一个
    Pop
    ,但编译器不会进行这种分析。)

  • Java编译器查看
    对象
    类,查找
    等于
    的匹配定义。
    equals只有一个定义,并且它匹配(即参数列表与定义兼容)。因此,Java字节码被创建为“我们正在调用
    对象中定义的方法
    equals

  • 在运行时,当调用时,它调用
    对象
    中定义的方法
    equals
    ,如字节码所示。不过,Java在任何时候进行调用时,都会使用覆盖调用(如果有)。因此它查看实际类
    Pop
    ,并查看
    Pop
    (或
    Object
    Pop
    之间的任何其他超类,但这里没有超类)是否覆盖
    Object
    中的该方法。
    Pop
    中的第一个方法会覆盖它,因此执行的就是这个方法,
    “O”
    会被打印出来。第二个
    equals
    方法根本不被考虑,因为它不会覆盖
    对象中的
    equals

  • 我不知道编译器使用什么机制来存储覆盖信息。但在我使用过的另一种不同语言的编译器中,方法在向量中获取索引或“槽”号。当定义
    对象
    时,其方法得到唯一的时隙;
    等于
    的时隙可能是,比如说,7。因此,向量中的第7个条目将是
    等于
    的地址。当定义了
    Pop
    时,由于第一个
    等于
    覆盖了
    对象
    中的一个,因此它也会得到插槽7。第二个
    等于
    不会覆盖任何内容,因此它会得到一个新的插槽号,可能是18。因此会有一个向量,其中索引7包含
    中第一个
    等于
    的地址,而索引18包含第二个
    的地址。现在,当代码在
    对象
    中调用
    等于
    时,代码会说类似于“调用插槽7中的任何方法”。对于
    Pop
    对象,插槽7中的方法将是第一个
    equals
    ,它将打印
    “O”
    。但它从不看18号槽。我怀疑Java确实是以这种方式运行的,但效果是相似的。基本上,有一些ID可以被查找,并调用该ID的方法;Java在运行时不会搜索类中定义的可能被调用的另一个方法

    更多:如果您真的想要它打印
    “p”
    的行为,如果它的参数是
    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;
        }
    

    因为重载解析(根据参数类型在方法中进行选择)是在编译时根据指定目标对象和方法参数的表达式的声明类型执行的。只有重写解析(根据调用它的对象的类型在给定签名的方法中进行选择)在运行时是动态发生的。Jashua Bloch在他的《有效Java》一书中正好论述了这种情况。[你可以在下面的答案中找到解释]()因为你没有研究什么是
    override
    以及什么时候发生的?@JohnBollinger你的意思是获得Pop的equals方法,因为参数实际上是重载,而不是重写?谢谢!这真的很有帮助。