gpt4 book ai didi

java - JVM 加载中的静态字段

转载 作者:行者123 更新时间:2023-12-02 02:20:06 25 4
gpt4 key购买 nike

作为 JVM 加载、链接和初始化的一部分,当

  1. 静态字段
  2. 最终静态字段

在类里面

  1. 在内存中分配
  2. init 作为默认值
  3. init 作为实际值

对于静态最终变量,我认为一切都发生在加载步骤中,因为所有值都已经在常量池中。

但我无法弄清楚静态字段发生了什么。原则上写在documantation它们在准备步骤中使用默认值进行初始化。

Preparation involves creating the static fields for a class or interface and initializing such fields to their default values (§2.3, §2.4). This does not require the execution of any Java Virtual Machine code; explicit initializers for static fields are executed as part of initialization (§5.5), not preparation.

但是在这个source (类变量段落)加载静态字段初始化已在加载步骤中发生。这是有道理的,因为在加载步骤结束时创建了类对象的实例,并且它必须包含静态字段的空间。

Before a Java virtual machine uses a class, it must allocate memory from the method area for each non-final class variable declared in the class.

所以我想知道在这种情况下正确的事实是什么。

最佳答案

一般来说,如果 the official specification 之间存在一些不匹配的情况以及互联网上的一些文章,您可以放心地假设规范具有最终结论并且文章是错误的。这将在 99.99% 的情况下为您服务。

当涉及到 Java 虚拟机时尤其如此,众所周知,其中的文章混淆了问题的步骤(“加载、链接和初始化”),并且还经常混淆正式步骤和实现细节。

您链接的文章在几个方面都有错误:

  • 并非每个 static final field 是一个编译时常量。仅static final原始类型的字段或 String是编译时常量,如果它们立即用编译时常量初始化。考虑一下

    static final String CONSTANT1 = ""; // compile-time constant
    static final String CONSTANT2 = CONSTANT1; // compile-time constant
    // but
    static final String NO_CONSTANT1 = CONSTANT1.toString(); // not a constant expression
    static final String NO_CONSTANT2; // no initializer
    static {
    NO_CONSTANT2 = ""; // assignment in class initializer, valid, but not constant
    }
    static final BigInteger NO_CONSTANT3 = BigInteger.ONE; // neither primitive nor String
  • 对于编译时常量,每个普通的 Java 语言读取访问都会在编译时被常量值替换,但标识符仍然存在,并且可以通过反射检查或通过不是从 Java 语言源生成的字节代码访问代码。当涉及到常量字段的存储时,JVM 是否对常量字段进行特殊处理是一个实现细节,但通常情况下,实现者会尽量避免特殊处理,除非有真正的好处。

    正式规范描述了常量变量,就像具有像任何其他变量一样的存储,但是当然,如​​果实现仍然能够保留规定的行为(例如,使值可用于反射),则实现可以省略这一点。

    常量和非常量的初始化 static变量明确指定为 Initialization 的一部分(虽然不是同时):

     

    1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize each final static field of C with the constant value in its ConstantValue attribute (§4.7.2), in the order the fields appear in the ClassFile structure.

     9. Next, execute the class or interface initialization method of C.

    “类或接口(interface)初始化方法”是名为<clinit>的方法在字节码级别,其中包含非常量 static 的所有初始值设定项字段以及 static { … } 中的任何代码块。

  • 类变量和常量池是不同的东西。常量池包含字段的符号名称以及编译时常量的值(顺便说一句,也可能包括非 static 字段)。

    常量池的值可用于构造实际的运行时值,例如描述字符串的字节序列必须转换为对实际 String 的引用对象和原始类型可能会进行 Endianess 转换。当此处理作为 JVMS§5.5 中描述的步骤 6 的一部分发生时(如上所述),对该字段的后续访问将始终使用此过程的结果。

关于java - JVM 加载中的静态字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48621815/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com