9

以下代码使用 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()方法的返回类型为SuperClassis List,在其子类中的返回类型为ArrayList。方法覆盖如何在这里工作?

顺便说一句,很明显这ArrayListList接口的实现,但是编译器在覆盖getList()方法时如何处理这里的返回类型?

我是否应该相信这样的事情......被覆盖方法的返回类型被允许是被覆盖方法的返回类型的子类型。

4

4 回答 4

20

是的。

在早期的 Java 中情况并非如此,但在 Java 5.0 中发生了变化。

同一个类中不能有两个方法,其签名仅因返回类型而异。在 J2SE 5.0 发布之前,一个类也确实不能覆盖它从超类继承的方法的返回类型。在本技巧中,您将了解 J2SE 5.0 中允许协变返回类型的新特性。这意味着子类中的方法可以返回一个对象,该对象的类型是该方法返回的类型的子类,在超类中具有相同的签名。此功能消除了对过多类型检查和强制转换的需要。

互联网上不再提供此信息的来源。

于 2012-04-13T02:41:57.310 回答
5

在面向对象编程中,方法的协变返回类型是在子类中重写该方法时可以用“更窄”类型替换的方法。这是一个相当普遍的范例的著名语言是 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 替换原则。

这通常意味着覆盖方法的返回类型将是被覆盖方法的返回类型的子类型。上面的例子具体说明了这种情况。如果不允许替换,则返回类型是不变的并导致编译错误。

参考:https ://en.wikipedia.org/wiki/Covariant_return_type

于 2012-07-05T08:51:27.077 回答
3

对,那是正确的。由于 ArrayList 是 List,因此当原始方法返回 List 时,您可以返回 ArrayList。

于 2012-04-13T02:43:37.147 回答
0

我用 javap 命令检查了 OPs 示例的字节码,发现编译器在 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();
于 2021-04-27T18:29:34.300 回答