【问题标题】:Why doesn't my primitive-type-argumented method override the wrapper-type-argumented super class method?为什么我的原始类型参数方法不覆盖包装器类型参数超类方法?
【发布时间】:2019-02-12 12:07:09
【问题描述】:
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。我在这里错过了什么?

【问题讨论】:

  • 它签入1指定的类WrapperClasses或wr。编译器不会(不需要)努力研究 wr 实际上是什么类。在WrapperClasses wr = System.millis() % 2 == 0? new WrapperClasses() : new mine();,这可能会变得无法解决。
  • 编译时接线。

标签: java wrapper autoboxing


【解决方案1】:

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

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】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

      在协变返回类型的情况下,编译器生成桥接方法以允许这种情况发生,但是,Java 语言规范不要求包装器与原语的这种桥接方法。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-08
        • 1970-01-01
        • 1970-01-01
        • 2020-02-11
        • 2012-12-21
        • 2018-07-07
        • 2015-02-18
        相关资源
        最近更新 更多