java - 使用协变类型替换wrt变量

时间:2015-05-04 08:26:50

标签: java override method-overriding ocpjp covariant

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引用?

2 个答案:

答案 0 :(得分:1)

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

声明的类型是你可以想到的对象,即你的例子中的G.

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

答案 1 :(得分: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引用,因为它未在运行时使用。编译器只使用引用的类型,正如您在问题中所预期的那样。