6

我制作了一个包含以下内容的类:

  1. static final多变的
  2. static带有System.out.println()语句的初始化块

如果我static final从另一个类调用变量,则该static块不会执行。

据我所知,static初始化程序块在类加载到内存时执行。

在这种情况下,内存级别发生了什么?

类没有加载到内存中吗?如果没有,其他类从哪里获得final static变量的地址?


情况 1: static块不执行

class Test2 {
    static final int a = 20;

    static {
        System.out.println("one");
    }
}

案例2: static确实执行

class Test2 {
    static final int a;

    static {
        a = 20;
        System.out.println("one");
    }
}

输出

class Test {
    public static void main(String[] args) {
        System.out.println(Test2.a);
    }
}
  • 情况1:

    20
    
  • 案例二:

    one
    20
    

那么在这两个层面上发生了什么?

4

2 回答 2

12

我的猜测是您的字段是原始类型或String, 并使用编译时常量表达式进行初始化。

对于使用常量表达式初始化的静态最终字段(并且只有这样的字段) - 任何引用该字段的代码都会将常量值烘焙到其中,而不是通过会导致类初始化的静态字段。不过,“常量表达式”部分很重要。我们可以通过一个小型测试应用程序看到这一点:

class Fields {
    
    public static final String CONSTANT = "Constant";
    public static final String NON_CONSTANT = new String("Non-constant");
    
    static {
        System.out.println("Initializing");
    }
}

public class Test {
    public static void main(String arg[]) {
        System.out.println(Fields.CONSTANT);
        System.out.println(Fields.NON_CONSTANT);
    }
}

输出是:

Constant
Initializing
Non-constant

访问常量字段不需要初始化,但访问非常量字段则需要。使用非最终字段将具有相同的效果:它基本上不再算作常数。

关于“这是一个常量”的信息被烘焙到声明一个字段的类中。例如,使用javap -c Fields我们看到两个字段:

public static final java.lang.String CONSTANT;
  flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
  ConstantValue: String Constant

public static final java.lang.String NON_CONSTANT;
  flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

请注意字段元数据中缺少的字段元数据ConstantValue部分。CONSTANTNON_CONSTANT

有关什么构成常量表达式的更多信息,请参阅JLS 的第 15.28 节。

JLS 的第 12.4.1 节指定了何时初始化一个类:

类或接口类型 T 将在以下任何一项第一次出现之前立即初始化:

  • T 是一个类,并创建了一个 T 的实例。

  • T 是一个类,并且调用了 T 声明的静态方法。

  • 分配了一个由 T 声明的静态字段。

  • 使用了由 T 声明的静态字段,并且该字段不是常量变量(第 4.12.4 节)

  • T 是一个顶级类(第 7.6 节),并且执行在词法上嵌套在 T(第 8.1.3 节)中的断言语句(第 14.10 节)。

(强调我的。)

于 2013-09-25T06:10:49.587 回答
11
  1. 静态 final 字段是编译时常量,其值被硬编码到目标类中,而不引用其来源;

  2. 因此您的主类不会触发包含该字段的类的加载;

  3. 因此该类中的静态初始化程序不会被执行。

final请参阅从定义中删除的魔法。您将看到静态初始化程序正在执行

于 2013-09-25T05:56:15.680 回答