Java "trick", 重新定义子类成员

标签 java inheritance

我正在为 Java 考试进行培训,我在去年的科目中遇到了一些我不理解的东西。这是代码

class Mother {
    int var = 2;

    int getVar() {
        return var;
    }
}

class Daughter extends Mother {
    int var = 1;

    int getVar() { 
        return var;
    }

    public static void main(String[] args) {
        Mother m = new Mother();
        System.out.println(m.var);
        System.out.println(m.getVar());
        m = new Daughter();
        System.out.println(m.var);
        System.out.println(m.getVar());
    }
}

问题是“这个程序的输出是什么?”。我会选择 2 2 1 1,但是在编译和运行这段代码时,我得到 2 2 2 1。

谁能告诉我为什么?

感谢阅读!

最佳答案

方法调用 m.getVar() 是一个虚拟方法调用。第二次调用它时,它会动态分派(dispatch)到派生的 Daughter.getVar(),它会执行您期望的操作(访问 Daugther.var 并返回它)。

成员字段没有这样的虚拟调度机制。所以 m.var 总是引用 Mother.var,即该变量的基类版本。

Daughter 类可以看作有两个不同的var 成员:一个来自Mother 和它自己的。它自己的成员“隐藏”了 Mother 中的成员,但可以使用 super.varDaughter 类中访问。

这方面的官方规范在 8.3 Field Declarations 部分的 JLS . 引用:

If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class. The field declaration also shadows (§6.3.1) declarations of any accessible fields in enclosing classes or interfaces, and any local variables, formal method parameters, and exception handler parameters with the same name in any enclosing blocks.

请注意,它会变得非常有趣(添加了重点):

If a field declaration hides the declaration of another field, the two fields need not have the same type.

和:

There might be several paths by which the same field declaration might be inherited from an interface. In such a situation, the field is considered to be inherited only once, and it may be referred to by its simple name without ambiguity.

所以该段非常值得一读:-)

关于Java "trick", 重新定义子类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6008472/

相关文章:

python - 如何在Python中的super()函数中指定使用哪个父类?

Java当前时间需要递增的方法

Java:如何集成其他软件

java - 在 target/classes 目录中运行 "java ivy.IVYbot.IVYbot.Main"返回找不到主类错误

java - 组织.hibernate.InstantiationException : Cannot instantiate abstract class or interface

javascript - 如何在javascript中继承基类属性并调用基类构造函数?

java - Tomcat - 在 VPS 上运行

java - 使用类名创建实例并调用构造函数

javascript - 没有 new 或 Object.create 的原型(prototype)继承

C# 继承多个父类