7

当我们说基类Base及其派生类Derived时,type compatible我们指的是Base引用可以引用Derived实例这一事实。
Base b = new Derived();
对于相反,将需要强制转换,因为类型不兼容。
现在这个概念不适用于原始类型吗?
我的意思是这个

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;  
    }  

}  
4

4 回答 4

7

直接的答案,为什么您的代码示例无效,很简单:协变返回类型的 Java 语言特性显式不适用于原语。请参阅JLS 8.4.5JLS 8.4.8.3

自动装箱不适用于此处。如果您将返回类型更改为Integerand Short,它们仍然不能返回类型替代,因为两者都不是另一个的子类。

我无法回答“为什么 JLS 不允许原语的协变返回类型”的问题,即为什么语言设计者决定不应该允许它。

于 2012-07-22T09:28:32.160 回答
3

从 Java 1.5 开始,您的 short 和 int 都可以自动装箱到Shortand Integer,并且 Short 不扩展 Integer(例如,它具有不同的 MAX_VALUE)。

这是造成问题的原因之一,但我认为真正的原因是这些 Java 语言设计决策之一:如果您要更改类型,我们希望您意识到这一点。

于 2012-07-22T09:16:37.923 回答
2

您不能根据返回类型覆盖方法,这是不允许的,编译器会抱怨它不会被视为被覆盖的方法。

此外,函数调用在返回类型的基础上也不是确定性的。例如,如果你打电话

someObj.getId();

编译器将如何确定应该调用哪个方法?从编译器的角度来看,您没有处理返回值并不重要。

于 2012-07-22T09:26:32.733 回答
2
  1. JLS #8.4.8.3:覆盖和隐藏的要求

    如果具有返回类型 R1 的方法声明 d1 覆盖或隐藏具有返回类型 R2 的另一个方法 d2 的声明,则 d1 必须是 d2 的返回类型可替换(第 8.4.5 节),否则会发生编译时错误。
    此规则允许协变返回类型 - 在重写方法时改进方法的返回类型。

  2. JLS #8.4.5:方法返回类型 - 对象和基元的处理方式不同(强调我的):

    具有返回类型 R1 的方法声明 d1 可以返回类型替代具有返回类型 R2 的另一个方法 d2,当且仅当以下条件成立时:

    • 如果 R1 无效,则 R2 无效。
    • 如果 R1 是原始类型,则 R2 与 R1 相同。
    • 如果 R1 是引用类型,则:
      • R1 是 R2 的子类型,或者 R1 可以通过未经检查的转换(第 5.1.9 节)转换为 R2 的子类型,或者
      • R1 = |R2|

至于您的初始示例,它称为扩展转换(short -> int),不适用于方法覆盖的上下文。

于 2012-07-22T09:58:40.570 回答