0
class G {

    int x = 5;
}

class H extends G {

    int x = 6;
}

public class CovariantTest {

    public G getObject() {
        System.out.println("g");
        return new G();
    }

    public static void main(String[] args) {
        CovariantTest c1 = new SubCovariantTest();
        System.out.println(c1.getObject().x);
        System.out.println(new H().x);
    }
}

class SubCovariantTest extends CovariantTest {

    public H getObject() {
        System.out.println("h");
        return new H();
    }
}

输出:

h
5
6

显然 main 方法中的两个 println 语句是不一样的。从类 SubCovariant 的 getObject 方法返回的新 H() 对象如何分配给 G 引用?

4

2 回答 2

1

G 是声明的类型,H 是实际的类型。

声明的类型是您可以将对象视为的类型,即示例中的 G。

实际类型是对象实际上是什么,即您的示例中的 H 。这提供了实际行为,包括它可能从包括 G 在内的父类继承的任何行为。

于 2015-05-04T08:34:27.323 回答
1

当你重写一个方法时,重要的是实例的类型,而不是引用的类型。这就是多态性的工作原理。

CovariantTest c1 = new SubCovariantTest();

这会转换引用的类型,但不会转换实现。如果你要这样做

System.out.println(c1.getClass());

这将打印

SubCovariantTest

因此,当您调用getObject()此实例时,此调用也就不足为奇了SubCovariantTest.getObject()


相比之下,static方法不遵循多态性。它们不能以相同的方式被覆盖(它们只能被隐藏)如果你getObject()在这两种情况下都设为静态,你会发现 c1.getObject()调用匹配的类型,c1因为要调用的方法是在编译时确定的,而不是运行时。事实上,你可以做到这一点。

public class CovariantTest {

    public G static getObject() {
        System.out.println("g");
        return new G();
    }

    public static void main(String[] args) {
        CovariantTest c1 = null;
        System.out.println(c1.getObject().x); // prints "g" "5"
    }
}

class SubCovariantTest extends CovariantTest {

    public H static getObject() {
        System.out.println("h");
        return new H();
    }
}

您可以null在此处访问参考,因为它在运行时不使用。正如您在问题中所期望的那样,编译器仅使用引用的类型。

于 2015-05-04T08:38:21.717 回答