我最近开始使用JAVA编程并且有一个问题要问。 假设我有一个SuperClass和一个SubClass,它扩展了SuperClass并尝试覆盖SuperClass中定义的方法,如下所示:
public class SuperClass{
public void method1(int val){
System.out.println("This is method in SuperClass.Val is:" + val);
}
}
我尝试在我的SubClass中扩展SuperClass并使用一个例外覆盖该方法,而不是在method1中声明的类型int
,我将参数的类型用作Integer
,如下所示:
public class SubClass extends SuperClass{
@Override
public void method1(Integer val){ ///compiler gives an error
}
}
编译器不允许使用SubClass方法的声明(我使用的是eclipse IDE)。为什么会这样?整数本质上是int的包装,那么为什么禁止这样的声明?
由于
答案 0 :(得分:3)
正式解释,正如您可能已经理解的那样,这两个函数具有不同的签名(正如Andrew Tobilko已经指出的那样),因此可能无法覆盖另一个。
所以,我认为通过提出这个问题,你真正要问的是“为什么会这样”,或者“为什么编译器无法解决问题以便让我这样做”。
所以,实际解释如下:
这是因为你可能在某个地方(某些不相关的类甚至)有一些方法接受SuperClass
作为参数,并试图像这样调用它的method1()
:
public void someMethod( SuperClass s )
{
s.method1( 7 );
}
当编译器发现这一点时,它会将7
作为参数传递给method1()
,它不会传递包裹的7
。但是,s
可能不是SuperClass
的实例,它可能是SubClass
的实例,如下所示:
/* some code somewhere */
someMethod( new SubClass() );
这是有效的,因为OOP中的原则称为Liskov Substitution Principle,表示
如果S是T的子类型,则类型T的对象可以用类型S的对象替换(即,类型S的对象可以替换类型为T的对象),而不改变该程序的任何期望属性(正确性) ,任务执行等。)。
这个原理允许你将new ArrayList<String>()
分配给List<String>
类型的变量,如果没有它,OOP中什么也行不了。
因此,编译器必须传递一个普通的原始7
,但SubClass
的接收方法会期望一个包裹7
,这是行不通的。因此,该语言规定这种隐式转换是无效的,以确保不会出现这种无意义的情况。
<强>修订强>
你可能会问,“为什么它不起作用?”答案是java中的原语对应于底层硬件的机器数据类型,而包裹的原语是对象。因此,在机器堆栈上,7
将由值7
的机器字表示,而包裹的7
将由0x46d7c8fe
表示,它将是一个指向包含包装7
的对象的指针。
答案 1 :(得分:2)
这只是因为你在方法@Override
之上添加了public void method1(Integer val)
语法,它要求编译器在基类中找不到它找不到的相同签名的方法,因此它给出了编译时间错误说明The method method1(Integer) of type SubClass must override a superclass method
。
了解您提出的问题
整数本质上是int的包装,那么为什么禁止这样的声明呢?
因为在任何类中你都可以用这些签名声明方法
class SuperClass
{
public void method1(int val){
System.out.println("This is method in SuperClass.Val is:" + val);
}
public void method1(Integer val){
System.out.println("This is method in SuperClass.Val is:" + val);
}
}
上述声明是有效的,因此@override
将尝试将该方法与基类中的精确签名匹配。
答案 2 :(得分:2)
Integer是int的包装器为什么重要?它们仍然是不同的类型。您可以使用具有相同名称的方法,它们只有一个具有基本类型而另一个具有匹配的包装类型。
int和Integer之间的唯一关系是:编译器在任何情况下都会插入一个转换,而另一个则需要转换。
因此,当您引用超类型并调用method1时,编译器会生成基本上传递基元的字节代码。如果在运行时使用实际的SubClass类,则重写的方法不会匹配该调用。
当然编译器可以用允许这种覆盖的样式编写,但它会导致其他问题:
如果决定是在运行时做出的,那么调用overriden方法对装箱/拆箱和检查来说会变得很昂贵,甚至可能会触发NullPointerExceptions
如果通过在编译时将所有内容转换为盒装类型来完成,则此类调用将触发常量装箱拆箱。
这也是禁止你有一个重载方法的构造,要么采用类型参数或基元,因为类型参数可能最终成为该基元的盒装类型,导致两个方法都相同。 / p>
答案 3 :(得分:-3)
Integer和int是不同的。您可以将Integer更改为int,或者删除&#34; @ Override&#34;