为什么我的原始类型参数方法不覆盖包装类型参数的 super class 方法?

Why doesn't my primitive-type-argumented method override the wrapper-type-argumented super class method?

public class WrapperClasses{
    void overloadedMethod(Number N){
        System.out.println("Number Class Type");
    }

    void overloadedMethod(Double D){
        System.out.println("Double Wrapper Class Type");
    }

    void overloadedMethod(Long L){
        System.out.println("Long Wrapper Class Type");
    }

    public static void main(String[] args){
        int i = 21;
        WrapperClasses wr = new WrapperClasses();

        //wr.overloadedMethod(i);
    }
}

class mine extends WrapperClasses{
    void overloadedMethod(int N){
        System.out.println("Integer Class Type");
    }
    public static void main(String[] args){
        int i = 21;
        WrapperClasses wr = new mine();

        wr.overloadedMethod(i);
    }
}

这会打印 Number Class Type.

我了解包装器class方法重载的规则:

  1. 如果您将原始数据类型作为参数传递给方法 调用时,编译器首先检查采用 与参数相同的数据类型。
  2. 如果这样的方法不存在,那么它会检查一个方法 采用比传递的更大的原始数据类型的定义 数据类型。即,它尝试执行自动加宽转换 传递的数据类型。
  3. 如果无法进行自动扩展转换,则会检查 方法定义,它将相应的包装器 class 类型作为 争论。即,它尝试执行自动装箱转换。
  4. 如果这样的方法不存在,那么它会检查一个方法 将超级 class 类型(数字或对象类型)作为参数。
  5. 如果这样的方法也不存在,那么编译器给出一个 编译时错误。

根据规则 1,它应该打印 Integer Class Type。我在这里错过了什么?

方法重载决议是在编译时确定的,基于变量的编译时类型,该变量持有对您为其调用方法的实例的引用。

void overloadedMethod(int N)只定义在子classmine中。因此,当您在类型为基 class WrapperClasses 的引用上调用方法时,只能考虑基 class 的方法进行重载解析。

您传递给该方法的 int 参数与基础 class 的 3 个方法中的任何一个都不匹配,但在装箱到 Integer 之后,它匹配void overloadedMethod(Number N) 方法。

如果您将代码更改为

    int i = 21;
    mine wr = new mine();

    wr.overloadedMethod(i);

它将执行void overloadedMethod(int N)

在语言规范级别,这是因为参数为原始类型和包装原始类型的方法不被视为 override-equivalent。 (一种奇特的说法 "they just don't because the language spec says so")。

但从逻辑上讲,它们也不应该,至少在 subint 参数的情况下 class "overriding" super[=26= 中的包装参数].

根据里氏替换原则,subclasses 中的方法必须接受至少 superclass 中的方法接受的所有参数。

如果superclass方法接受包裹的class,它可以接受null。如果subclass方法只允许接受int,它不能接受null,所以它是不可替代的。

多态性由 JVM 在运行时执行。为此,这两个方法必须具有相同的运行时签名。

在协变 [​​=18=] 类型的情况下,编译器生成桥接方法以允许这种情况发生,但是,Java 语言规范不需要这样的桥接方法用于包装器与基元.

这可能有多种原因,但最有可能是向后兼容性。 Java 1.0 没有这样做,即使十多年后添加了自动装箱,也不允许破坏旧代码。即包装器和原语相互重载,而不是覆盖,所以他们现在不能。