java - 为什么Java在编译时绑定(bind)变量?

标签 java inheritance jls

考虑以下示例代码

class MyClass {
    public String var = "base";

    public void printVar() {
        System.out.println(var);
    }
}

class MyDerivedClass extends MyClass {
    public String var = "derived";

    public void printVar() {
        System.out.println(var);
    }
}

public class Binding {
    public static void main(String[] args) {
        MyClass base = new MyClass();
        MyClass derived = new MyDerivedClass();

        System.out.println(base.var);
        System.out.println(derived.var);
        base.printVar();
        derived.printVar();
    }
}

它给出以下输出

base
base
base
derived

方法调用在运行时得到解决,并按预期调用正确的覆盖方法。
正如我后来了解到的,变量访问是在编译时解决的。 我期待输出为

base
derived
base
derived

因为在派生类中重新定义 var 会影响基类中的定义。
为什么变量的绑定(bind)发生在编译时而不是运行时?这仅仅是出于性能原因吗?

最佳答案

原因在 Java 语言规范中的 Section 15.11 示例中进行了解释。 ,引述如下:

...

The last line shows that, indeed, the field that is accessed does not depend on the run-time class of the referenced object; even if s holds a reference to an object of class T, the expression s.x refers to the x field of class S, because the type of the expression s is S. Objects of class T contain two fields named x, one for class T and one for its superclass S.

This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used...

所以是的,性能是一个原因。字段访问表达式的求值方式规范如下:

  • If the field is not static:

    ...

    • If the field is a non-blank final, then the result is the value of the named member field in type T found in the object referenced by the value of the Primary.

在您的情况下,Primary 是指 derived 类型的变量 MyClass

另一个原因,正如@Clashsoft 建议的那样,是在子类中,字段没有被覆盖,它们是隐藏。因此,允许基于声明的类型或使用强制类型转换访问哪些字段是有意义的。这也适用于静态方法。这就是为什么根据声明的类型确定字段的原因。与依赖于实际类型的实例方法覆盖不同。上面的 JLS 引用确实含蓄地提到了这个原因:

The power of late binding and overriding is available, but only when instance methods are used.

关于java - 为什么Java在编译时绑定(bind)变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422923/

相关文章:

java - 编写 Java 代码需要域名吗?

java - 存储在字符串池中的字符串文字是否唯一?

java - 如何从数组中删除重复项

java - 使用 Hibernate Search 和 Lucene 实现类似 Google 的搜索

java - 降级到 Java 6

java - 使用 Metro 编码 JAXB 类时忽略 schemaLocation

Java:如何将几个类的方法链接到一个对象中?

java - 将派生类传递给需要覆盖期望基类的方法

java - JPA继承问题

java - 在Java中,为什么我不能写i++++或(i++)++?