Java中的协变返回类型
下面的代码使用Java中的方法重写概念Java中的协变返回类型,java,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;
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);
}
}
}
package-pkg;
导入java.util.ArrayList;
导入java.util.List;
抽象类超类
{
抽象公共ListgetList();
}
最后一个类子类扩展了超类
{
private Listlist=null;
@凌驾
公共ArrayList getList()
{
列表=新的ArrayList();
列表。添加(“A”);
列表。添加(“B”);
返回(ArrayList)列表;
}
}
最终公开课主
{
公共静态void main(字符串[]args)
{
超类s=新的子类();
Listlist=s.getList();
for(字符串str:list)
{
系统输出打印项次(str);
}
}
}
按照约定,方法重写在超类和子类中使用相同的签名(返回类型)。在上面的代码中,超类中的getList()
方法的返回类型是List
,在其子类中返回类型是ArrayList
。方法重写在这里是如何工作的
顺便说一下,ArrayList
显然是List
接口的一个实现,但是编译器在重写getList()
方法时如何处理这里的返回类型呢
我应该相信这样的事情吗。。。被重写方法的返回类型可以是被重写方法的返回类型的子类型。是
在早期java中情况并非如此,但在Java5.0中有所改变
同一类中不能有两个方法的签名仅在返回类型上不同。在J2SE5.0发布之前,类不能重写从超类继承的方法的返回类型也是事实。在本技巧中,您将了解J2SE 5.0中允许协变返回类型的一个新特性。这意味着子类中的方法可能返回一个对象,该对象的类型是该方法返回的类型的子类,该方法在超类中具有相同的签名。此功能消除了过度类型检查和强制转换的需要
这些信息的来源在互联网站上不再可用。是的,这是正确的。因为ArrayList是一个列表,所以当原始方法返回列表时,可以返回ArrayList。在面向对象编程中,方法的协变返回类型是在子类中重写该方法时可以用“更窄”类型替换的类型。一个著名的语言,这是一个相当常见的范例是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替代原则将一种类型替换为另一种类型
这通常意味着重写方法的返回类型将是重写方法的返回类型的子类型。上面的示例具体说明了这种情况。如果不允许替换,则返回类型是不变的,并导致编译错误
参考资料:我用javap命令检查了OPs示例的字节码,发现编译器在子类中生成了一个额外的方法:
//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();
似乎没有很好的理由将子类.list
声明为列表
(而不是数组列表
)。@MichaelBrewer-Davis-如果你直接使用子类
,而不是将其视为超类
。@Brendan-我说的是(私有)成员变量太一般,而方法太具体。方法中的协方差是阳光和蝴蝶。@MichaelBrewer Davis仔细检查后发现,SubClass.list
根本不存在。链接已失效。