Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当对象的所有字段都设置为默认值时,为什么实例常量有一个值?_Java_Polymorphism - Fatal编程技术网

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

Java 当对象的所有字段都设置为默认值时,为什么实例常量有一个值?,java,polymorphism,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&

代码如下:

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没有完全初始化,当我们从超类构造函数调用方法“action”时,变量“field”有一个默认值,但最终变量“finalField”已经有值42


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

当最后一个字段用a初始化时,它被称为a:

这意味着字符串

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

通常,当使用常量变量字段时,必须在编译时将其替换为其值。要在运行时引用该字段,请执行以下操作:

  • 对常量变量(§4.12.4)字段的引用必须在编译时解析为常量变量初始值设定项表示的值V

    如果这样的字段是非静态的,则二进制文件中的代码中不应存在对该字段的引用,包含该字段的类除外。(它将是一个类而不是一个接口,因为接口只有静态字段。)该类应该有代码在实例创建期间将字段的值设置为V(§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中有两种类型的流

  • 静态流动
  • 实例流
  • 静态流量

    每当我们执行父子类时,下面的事件序列将 将自动执行

    • 从父级到子级的静态成员标识

    • 从父级到子级执行静态变量赋值和静态块

    • 独子类main的执行

    实例流

    • 无论何时执行Java类,都将首先执行静态控制流

    • 从父级到子级的实例成员标识

    • 仅在父级中执行实例变量分配和实例块 阶级

    • 父类构造函数的执行

    • 在子类中执行实例变量赋值和实例块

    • 子类构造函数的执行

    基于这些规则,我将尝试解释jvm是如何执行代码的

  • 标识静态成员:->公共静态void main(字符串[]args)

  • 执行主方法

  • 首先标识类中的实例成员,然后标识B类中的实例成员

  • //A班成员

    受保护的无效行为()

    //B班成员

    私人最终int finalField=42;(由于这是最终版本,编者将直接对其进行分类)

    私有整型字段=0;(添加此成员的默认值)

    公共无效诉讼()

  • 仅在父级中执行实例变量分配和实例块
  • //没有可分配的成员

  • 执行父构造函数

    B构造函数中的第一行是super(),因此控件将放在类构造函数中

    System.out.println(“之前的构造函数”)

    动作()//这有点棘手,因为这两种方法都已经存在 鉴定 通过编译器,jvm有两个选项可供选择:类中的action()或 动作()B,但是 。因为操作方法在B类中被重写,而被重写的方法在java中被重写 使用 运行时,它将在B类中执行action()方法

    //此时,字段的值为0

    System.out.println(“后面的构造函数”)

  • 仅在子系统中执行实例变量分配和实例块 阶级

  • 专用整型字段=99

  • 执行子类构造函数

  • 图灵的链接有答案,但格式清晰,这是一个很好的问题。dupe对我来说似乎不正确,它似乎无法解释
    字段
    最终字段
    的初始化顺序似乎不同。(查看字节码,在调用A的构造函数后,field和finalField都在B的构造函数中初始化,所以这里发生了其他事情)。投票表示感谢!我通过link阅读了这篇文章,但我仍然有一个问题,为什么final变量没有设置为默认值(在本例中为0)。看看字节码,看看普通字段和final字段之间有什么不同。谢谢。我需要了解更多。理解“final”有问题吗 case@RomanFrolov对于最后一种情况,我认为这很简单。您只需要知道,在jvm开始执行程序之前,每个最终变量都是在编译时计算的。就是这样!我现在可以安心睡觉了:)
    A constructor before
    B action, finalField=0, field=0
    A constructor after
    B constructor
    B action, finalField=42, field=99