静态最终变量以及静态初始化块

时间:2013-09-25 05:51:23

标签: java

我创建了一个包含以下内容的类:

  1. static final变量
  2. static带有System.out.println()语句的初始化程序块
  3. 如果我从另一个类调用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
      
    • 案例2:

      one
      20
      

    那么两个层面都发生了什么?

2 个答案:

答案 0 :(得分:11)

  1. 静态final字段是编译时常量,其值为 硬编码到目标类而不引用它 原点;

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

  3. 因此不会执行该类中的静态初始值设定项。

  4. 从定义中查看魔术删除final。您将看到执行静态初始化程序

答案 1 :(得分:11)

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

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

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

访问常量字段需要初始化,但访问非常量字段会执行。使用非final字段会产生相同的效果:它基本上不再算作常量。

关于“这是一个常数”的信息被引入声明一个字段的类中。例如,使用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字段元数据的CONSTANT部分,NON_CONSTANT字段元数据中缺少此部分。

有关构成常量表达式的更多信息,请参阅section 15.28 of the JLS

Section 12.4.1 of the JLS指定何时初始化类:

  

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

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

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

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

  •   
  • T声明的静态字段使用,字段不是常量变量(§4.12.4)

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

  •   

(强调我的。)