【问题标题】:Overriding equals()覆盖等于()
【发布时间】:2016-12-18 06:11:42
【问题描述】:

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

【问题讨论】:

  • 因为overload解析——在基于参数类型的方法中选择——是在编译时执行的,基于指定目标对象和方法的表达式的声明类型论据。只有override解决方案——根据调用它的对象的类型在给定签名的方法中进行选择——在运行时动态发生。
  • Jashua Bloch 在他的书Effective Java 中正是针对这种情况。
  • [您可以在下面的答案中找到解释](stackoverflow.com/questions/30109231/…)
  • 因为您没有研究override 是什么以及何时它会发生?
  • @JohnBollinger 你的意思是获取 Pop 作为参数的 equals 方法实际上是 overload,而不是 override我>?

标签: java overriding


【解决方案1】:

当您编码 o.equals(p1) 时会发生以下情况:

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

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

  3. 在运行时,当进行调用时,它会调用定义在Object 中的方法equals,就像字节码所说的那样。但是,只要 Java 进行调用,它就会使用一个覆盖调用(如果有的话)。因此,它查看实际的类Pop,并查看Pop(或ObjectPop 之间的任何其他超类,但这里没有)是否覆盖Object 中的该方法。 Pop 中的第一个方法确实覆盖了它,所以这就是执行的方法,"O" 被打印出来。第二个equals 方法根本没有被查看,因为它不会覆盖Object 中的equals

我不知道编译器使用什么机制来存储覆盖信息。但在我使用过的另一种不同语言的编译器中,方法在向量中获取索引或“槽”数字。当Object 被定义时,它的方法获得唯一的槽; equals 的插槽可能是,比如说,7。所以向量中的第 7 个条目将是 equals 的地址。当Pop 被定义时,因为第一个equals 覆盖了Object 中的那个,它也会得到槽7。第二个equals 没有覆盖任何东西,所以它得到一个新的槽号,可能是18。所以会有一个向量,其中索引 7 包含 Pop 中第一个 equals 的地址,索引 18 包含第二个地址。现在,当代码在Object 中调用equals 时,代码会显示类似“调用插槽7 中的任何方法”的内容。对于Pop 对象,插槽7 中的方法将是第一个equals,它打印"O"。但它从不查看 slot 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;
    }

【讨论】:

  • 谢谢!这真的很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-31
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 2016-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多