Java 为什么重写方法时类型兼容性也不适用于原语?
当我们说基类Java 为什么重写方法时类型兼容性也不适用于原语?,java,inheritance,polymorphism,overriding,Java,Inheritance,Polymorphism,Overriding,当我们说基类Base及其派生类derived与类型兼容时,我们指的是Base引用可以引用派生的实例。 即Base b=新派生() 对于oposite,由于类型不兼容,需要进行转换。 这个概念不适用于基本类型吗? 我是说这个 short shortNumber = 10; int intNumber = shortNumber; 对我来说似乎是一样的(因为也不需要强制转换,而且short和int都是整数类型)。 因此,当在基类中覆盖方法时,为什么可以接受返回类型与基类的返回类型相同或至少
Base
及其派生类derived
与类型兼容时,我们指的是Base
引用可以引用派生的实例。
即Base b=新派生()代码>
对于oposite,由于类型不兼容,需要进行转换。
这个概念不适用于基本类型吗?
我是说这个
short shortNumber = 10;
int intNumber = shortNumber;
对我来说似乎是一样的(因为也不需要强制转换,而且short
和int
都是整数类型)。
因此,当在基类中覆盖方法时,为什么可以接受返回类型与基类的返回类型相同或至少与基类的返回类型兼容,但这不适用于整数类型(例如?
例如,为什么这是不可接受的
public class Person {
public int getId(){
return 1;
}
}
public class Employee extends Person {
public short getId(){
return 0;
}
}
自Java 1.5以来,您的Short和int都可以自动装箱到Short
和Integer
,Short不扩展Integer(例如,它具有不同的MAX_值)
这是造成问题的一个原因,但我认为真正的原因是java语言设计决策之一:如果您要更改类型,我们希望您了解它。您不能基于返回类型重写方法,这是不允许的,编译器会抱怨它不会被视为被重写的方法
函数调用也不是基于返回类型的确定性的。例如,如果你打电话
someObj.getId()
编译器将如何确定应该调用哪个方法?从编译器的角度来看,您没有处理返回值并不重要。直接的答案,为什么您的代码示例无效,很简单:协变返回类型的Java语言特性显式地不适用于原语。见和
自动装箱在这里不适用。如果您将返回类型更改为Integer
和Short
,它们仍然是不可替换的返回类型,因为两者都不是另一个的子类
我无法回答“为什么JLS不允许原语使用协变返回类型”的问题,即为什么语言设计者决定不允许协变返回类型
:覆盖和隐藏中的要求
如果返回类型为R1的方法声明d1重写或隐藏另一个返回类型为R2的方法d2的声明,则d1必须是d2的可替换返回类型(§8.4.5),否则会发生编译时错误。
此规则允许协变返回类型—在重写方法时优化方法的返回类型
:方法返回类型-对象和原语的处理方式不同(强调):
当且仅当以下条件成立时,返回类型为R1的方法声明d1可替换为返回类型为R2的另一方法d2:
- 如果R1无效,则R2无效
- 如果R1是基元类型,则R2与R1相同。
- 如果R1是引用类型,则:
- R1是R2的子类型,或者R1可以通过未经检查的转换(§5.1.9)转换为R2的子类型,或者
- R1=| R2|
至于您最初的示例,它被称为加宽转换(short->int),不适用于方法重写的上下文。原语不是多态的。@duffymo:我只是指返回类型,不管在哪里引用它们,它都是真的。@user384706为什么不更改名称?索博兰:我想是因为懒惰。为什么?SoboLAN的意思是否比userXXXX更重要?编译器可以在运行时根据someObj
变量的实际对象引用来确定它,但是如果在同一个类中声明了具有相同签名和不同返回类型的方法呢?它会产生歧义,这就是为什么它在任何地方都不被允许(在您的情况下是继承)。事件如果返回类型完全不同,它们将产生歧义。原语不会相互扩展,因此没有什么可共同变化的。但是,当我转换为更广泛的类型时,信息不会丢失。这些类型在某种程度上是兼容的