[英]Covariant return type in Java
以下代码使用了 Java 中方法覆盖的概念。
package pkg;
import java.util.ArrayList;
import java.util.List;
abstract class SuperClass
{
abstract public List<String>getList();
}
final class SubClass extends SuperClass
{
private List<String>list=null;
@Override
public ArrayList<String> getList()
{
list=new ArrayList<String>();
list.add("A");
list.add("B");
return (ArrayList<String>) list;
}
}
final public class Main
{
public static void main(String[] args)
{
SuperClass s=new SubClass();
List<String>list=s.getList();
for(String str:list)
{
System.out.println(str);
}
}
}
按照惯例,方法覆盖在超类和子类中使用相同的签名(带有返回类型)。 在上面的代码中,的返回类型getList()
的方法中SuperClass
是List
,并在其子类返回类型为ArrayList
。 方法覆盖在这里如何工作?
顺便说一句,很明显ArrayList
是List
接口的实现,但是编译器在覆盖getList()
方法时如何处理这里的返回类型?
我应该相信这样的事情吗...重写方法的返回类型允许是重写方法的返回类型的子类型。
是的。
在早期的 Java 中并非如此,但在 Java 5.0 中发生了变化。
同一类中不能有两个方法的签名仅因返回类型不同而不同。 在 J2SE 5.0 发布之前,类不能覆盖它从超类继承的方法的返回类型也是事实。 在本技巧中,您将了解 J2SE 5.0 中允许协变返回类型的新特性。 这意味着子类中的方法可能返回一个对象,该对象的类型是超类中具有相同签名的方法返回的类型的子类。 此功能消除了对过度类型检查和强制转换的需要。
互联网上不再提供此信息的来源。
在面向对象编程中,当方法在子类中被重写时,方法的协变返回类型可以被“更窄”的类型替换。 一个值得注意的语言是 C++。 自 JDK5.0 发布以来,Java 语言已(部分)允许协变返回类型,因此以下示例无法在先前版本中编译:
// Classes used as return types:
class A {
}
class B extends A {
}
// "Class B is more narrow than class A"
// Classes demonstrating method overriding:
class C {
A getFoo() {
return new A();
}
}
class D extends C {
B getFoo() {
return new B();
}
}
更具体地说,协变(从宽到窄)或逆变(从窄到宽)返回类型是指将覆盖方法的返回类型更改为与原始覆盖方法的返回类型相关(但不同)的类型的情况.
两种协变返回类型之间的关系通常是一种关系,它允许根据 Liskov 替换原则将一种类型替换为另一种类型。
这通常意味着覆盖方法的返回类型将是覆盖方法的返回类型的子类型。 上面的例子具体说明了这种情况。 如果不允许替换,则返回类型是不变的并导致编译错误。
对,那是正确的。 由于 ArrayList 是一个 List,所以当原始方法返回一个 List 时,您可以返回一个 ArrayList。
我使用 OPs 示例的 javap 命令检查了字节码,发现编译器在 SubClass 类中生成了一个附加方法:
//1
public java.util.List getList();
它调用
//2
public java.util.ArrayList getList();
方法并返回它的结果。
SubClass sc=new SubClass();
//the ArrayList getList() will be invoked:
sc.getList();
SuperClass s=...;
//the List getList() will be invoked:
s.getList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.