java - 为什么看起来调用了错误的方法?

标签 java inheritance overriding overloading method-invocation

假设我有两个类 ABB 继承自 AB 有以下方法:

public boolean equals(Object other) {
   System.out.print("Object");
   return true;
}
public boolean equals(A other){
   System.out.print("A object");
   return true;
} 
public boolean equals(B other) {
   System.out.print("B object");
   return true;
}
A a1 = new A();
A ab = new B();
B b1 = new B();

我不清楚的是为什么

 ab.equals(a1)
 ab.equals(b1)

返回对象

abB 的实例,指针为 Aa1 显然既是 A 的实例又是指针。那么为什么它使用 Object other 而不是 A other 方法呢?对于 b1 也是如此,它是带有 pointe BB 实例,但编译器选择应用 equals 方法,就像我插入常规对象一样?我有那么蠢吗?还是这种语言不连贯?

顺便说一句,A根本没有任何equals方法。

最佳答案

说明

BTW A doesn't have any equals methods at all.

但是你知道

ab.equals(a1)
ab.equals(b1)

ab是:

A ab = new B();

因此,虽然它实际上是一个 B,但该变量的类型是 A

在这种情况下选择方法的 Java 规则将开始在 A 类中查找 equals 方法。它实际上有一个,即从 Object 继承的默认实现。它有签名

public boolean equals(Object other)

所以它决定了这个签名。现在,它向 ab 后面的实际实例(类型为 B)询问具有该签名的方法。它选择 B 中的重写实现:

public boolean equals(Object other) {
   System.out.print("Object");
}

在这两种情况下都会打印 Object


详细信息

这方面的详细信息在 JLS§15.12. Method Invocation Expressions 中定义。 。它谈到寻找最具体的匹配。如果您深入研究,规则可能会变得非常复杂。

一些摘录:

The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to search for definitions of methods of that name.

The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.

There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.

The class or interface determined by compile-time step 1 (§15.12.1) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

关于java - 为什么看起来调用了错误的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60362227/

相关文章:

java - 我可以将基类的对象分配给其子类的对象吗?

java - Photoshop "Pucker Tool"算法

c# - 从内部派生的公共(public)接口(interface)?

jquery - 删除应用于特定类型元素的 css

delphi 重载、重写、虚方法

html - 覆盖 CSS 移除属性

java - 如何将透明png设置为JButton?

Java .forEach(list::add) 与 .collect(Collectors.toList())

python - 覆盖python中的递归方法

C++派生类用另一个派生类覆盖基类的成员?