Java方法覆盖和变量阴影

时间:2014-09-15 11:43:11

标签: java inheritance

public class Circle {
    public float r = 100;
    public float getR() {
        return r;
    }
}

public class GraphicCircle extends Circle {
    public float r = 10;
    public float getR() {
        return r;
    }

    // Main method
    public static void main(String[] args) {
        GraphicCircle gc = new GraphicCircle();
        Circle c = gc;
        System.out.println("Radius = " + gc.r);
        System.out.println("Radius = " + gc.getR());
        System.out.println("Radius = " + c.r);
        System.out.println("Radius = " + c.getR());
    }

}

嗨,我无法理解上面代码的输出。输出是:

Radius = 10.0
Radius = 10.0
Radius = 100.0
Radius = 10.0

我理解为什么gc.r是10.我也理解为什么gc.getR()是10(因为GraphicCircle中的getR()方法会覆盖Circle的getR()方法)。但是我不明白为什么c.r是100,而c.getR()是10(当你按照上面的代码进行类型转换为祖先类时,我很难理解继承中会发生什么)。

3 个答案:

答案 0 :(得分:6)

Java中的方法调用是虚拟,这意味着无论您用于访问对象的引用是什么类型,都会调用对象的实际类型的方法。另一方面,直接字段访问不是虚拟的,因此您访问的r将取决于您通过它访问它的引用类型。

答案 1 :(得分:6)

您可以覆盖方法,而不是字段或类变量。因此getR()被覆盖,它实际上显示了您所期望的内容。

c.r访问圈子的类变量,而不是GC。

将类变量公开也是一个坏习惯。它们应该是私有的或至少受到保护,并使用getter和setter(more about private fields)来访问它们。

答案 2 :(得分:3)

首先,字段r不是阴影,它是隐藏

其次,关于覆盖方法的技术术语称为动态绑定。这只是意味着在运行时查找正在调用的方法时正在查询实例的实际类。

另一方面,对于字段,我们有静态绑定。这意味着编译器已经解析了所有字段访问,并且编译器只知道声明的类型

所以结论是:

System.out.println("Radius = " + c.r);

这会打印100.0,因为变量的类型为Circle,因此编译器会将对字段Circle.r的访问权写入字节代码。