为什么不允许在重写方法中使用参数类型(一个是原始的而另一个是包装器)的区别?

nee*_*rle 6 java polymorphism inheritance

我最近开始使用JAVA编程并且有一个问题要问.假设我有一个SuperClass和一个SubClass,它扩展了SuperClass并尝试覆盖SuperClass中定义的方法,如下所示:

  public class SuperClass{
    public void method1(int val){
      System.out.println("This is method in SuperClass.Val is:" + val);
      }
  }
Run Code Online (Sandbox Code Playgroud)

我尝试在我的SubClass中扩展SuperClass并使用一个例外覆盖该方法,而不是int在method1中声明的类型,我使用参数的类型Integer,如下所示:

  public class SubClass extends SuperClass{
    @Override 
    public void method1(Integer val){     ///compiler gives an error

     }
  }  
Run Code Online (Sandbox Code Playgroud)

编译器不允许使用SubClass方法的声明(我正在使用eclipse IDE).为什么会这样?整数本质上是int的包装,那为什么禁止这样的声明呢?

谢谢

Mik*_*kis 3

正如您可能已经理解的那样,正式的解释是这两个函数具有不同的签名(正如 Andrew Tobilko 已经指出的那样),因此一个函数可能不会覆盖另一个函数。

因此,我认为通过问这个问题,您真正想问的是“为什么会这样”,或者“为什么编译器不能弄清楚事情以便允许我这样做”。

所以,实际的解释如下:

这是因为你可能在某个地方有一些方法(甚至是一些不相关的类),它接受 aSuperClass作为参数,并尝试method1()像这样调用它:

public void someMethod( SuperClass s )
{
    s.method1( 7 );
}
Run Code Online (Sandbox Code Playgroud)

当编译器发现它时,它将7作为参数传递给method1(),而不会传递包装的7. 然而,s可能不是真正的实例SuperClass,它可能是实例SubClass,如下所示:

/* some code somewhere */
someMethod( new SubClass() );
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为 OOP 中有一个称为里氏替换原则的原则,它说:

如果 S 是 T 的子类型,则类型 T 的对象可以替换为类型 S 的对象(即类型 S 的对象可以替换类型 T 的对象),而不改变该程序的任何所需属性(正确性、执行的任务) , ETC。)。

new ArrayList<String>()这与允许您将 a 分配给类型变量的原则相同List<String>,没有它,OOP 中什么都不起作用。

因此,编译器必须传递一个普通的原语7,但 的接收方法SubClass将需要一个wrapped 7,这是行不通的。因此,语言规定这种隐式转换是无效的,以确保不会出现这种无意义的情况。

修正案

你可能会问:“为什么它不起作用?” 答案是,java中的原语对应于底层硬件的机器数据类型,而包装的原语是对象。因此,在机器堆栈上, a7将由值为 的机器字表示7,而wrapped7将由类似 的东西表示0x46d7c8fe,它是指向包含wrapped 的对象的指针7