为什么我的原始类型参数化的方法不能覆盖wrapper-type-argumented的超类方法?

时间:2018-09-07 07:25:57

标签: java wrapper autoboxing

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

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

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

根据规则1,应打印Integer Class Type。我在这里想念什么?

3 个答案:

答案 0 :(得分:10)

在语言规范级别,这是因为参数不同的方法被视为原始类型和包装原始类型的方法不被视为override-equivalent。 (一种奇特的说法是“他们只是不这样做,因为语言规范是这样说的”)。

但从逻辑上讲,至少在子类中的int参数“覆盖”超类中的包装参数的情况下,它们也不应该。

根据Liskov的替换原理,子类中的方法必须至少接受 超类中该方法所接受的所有参数。

如果超类方法接受包装的类,则它可以接受null。如果子类方法只允许接受int,则它不能接受null,因此它不能被替代。

答案 1 :(得分:5)

方法重载分辨率是在编译时根据变量的编译时类型确定的,该变量包含对要为其调用方法的实例的引用。

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

您传递给方法的int参数与基类的3个方法都不匹配,但是在将其装箱到Integer后,它与void overloadedMethod(Number N)相匹配方法。

如果您将代码更改为

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

    wr.overloadedMethod(i);

它将执行void overloadedMethod(int N)

答案 2 :(得分:3)

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

对于协变返回类型,编译器会生成允许这种情况发生的桥接方法,但是,Java语言规范对于包装程序与基元不需要这种桥接方法。

这可能有很多原因,但是最可能的原因是向后兼容。 Java 1.0并没有做到这一点,即使十多年后添加了自动装箱功能,也不允许这样做破坏旧代码。即包装器和基元彼此过载,而不是覆盖,因此它们现在不能。