java - 当对象的所有字段都设置为默认值时,为什么实例常量有值?

标签 java polymorphism

代码如下:

public class Main {
    public static void main(String[] args) {
        new B();
    }
}

class A {
    A() {
        System.out.println("A constructor before");
        action();
        System.out.println("A constructor after");
    }

    protected void action() {
        System.out.println("Never called");
    }
}

class B extends A {
    private final int finalField = 42;
    private int field = 99;

    B() {
        System.out.println("B constructor");
        action();
    }

    public void action() {
        System.out.println("B action, finalField=" + finalField + ", field=" + field);
    }
}

结果是:

A constructor before
B action, finalField=42, field=0
A constructor after
B constructor
B action, finalField=42, field=99

我被这一行弄糊涂了:

B action, finalField=42, field=0

对象 B 未完全初始化,当我们从父类(super class)构造函数调用方法“action”时 - 变量“field”具有默认值,但最终变量“finalField”已经具有值 42。

“finalField”是什么时候初始化的?

最佳答案

当一个 final 字段被初始化为 constant expression (15.29) , 它被称为 constant variable (4.12.4) :

private final int finalField = 42;

这意味着字符串

"B action, finalField=" + finalField + ", field="

本身是一个常量表达式,它的值是在编译时确定的。如果您检查已编译的类文件,您实际上会在常量池部分找到字符串 B action, finalField=42, field=

一般来说,当一个字段是一个常量变量时​​,它必须在编译时被它的值替换。是not allowed (13.1)在运行时引用字段:

  1. A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

    If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).

字段初始值设定项仍按您预期的方式运行:在 A 构造函数返回之后和 B 构造函数启动之前。观察未初始化的值很棘手,因为编译器内联变量的使用,但您可以通过反射访问字段的值:

public void action() {
    try {
        System.out.println("B action, finalField="
            + getClass().getDeclaredField("finalField").get(this)
            + ", field=" + field);
    } catch (IllegalAccessException | NoSuchFieldException e) {
        e.printStackTrace();
    }
}

输出:

A constructor before
B action, finalField=0, field=0
A constructor after
B constructor
B action, finalField=42, field=99

关于java - 当对象的所有字段都设置为默认值时,为什么实例常量有值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63436203/

相关文章:

JavaFX 2 按钮大小填充宽度和每个相同的宽度?

c++ - 链接器如何处理定义在多个头文件中的虚函数?

oop - 在这种情况下如何替换 instanceof ?

java - 面向对象编程 - 避免 Switch/Case 和 If/else (JAVA)

java - 应用不显示?

java - JPA如何在不创建表的情况下查询数据库

java - java中SDO和JDO的区别

c++ - 未找到方法 : Templates, 虚拟方法、继承、多态性

c++ - 如何正确使用 "C++ Core Guidelines: C.146: Use dynamic_cast where class hierarchy navigation is unavoidable"

java - 使用 Eclipse 插件 Jigloo 进行 GUI 编程