静态变量的奇怪行为

sto*_*s72 7 java

我上课了AbstractsAndInterfaces:

public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
private static final int DELTA = 5;

private static int BASE = 7;

private int x;
public AbstractsAndInterfaces()
{
    //System.out.println(BASE);
    //System.out.println(DELTA);
    x = BASE + DELTA;
}
public static int getBASE()
{
    return BASE;
}

   /**
 * @param args the command line arguments
 */
public static void main(String[] args) {

    System.out.println(AbstractsAndInterfaces.instance.x);
}
Run Code Online (Sandbox Code Playgroud)

为什么打印5?

为什么BASE变量未初始化?

The*_*ind 10

那是因为 :

private static final int DELTA = 5;将是一个编译时常量.因此,当类初始化(加载一次)后,5已经可用(初始化).

执行的第一行是: public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();

所以,现在你将去:

public AbstractsAndInterfaces()
{
    //System.out.println(BASE);
    //System.out.println(DELTA);
    x = BASE + DELTA; // same as x= 0+5 i.e default value of fields + constant value 5
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,DELTA将是5但是BASE因为它不是0 final.更改BASE为final将更改结果12.

编辑:

用于显示具有字节代码的OP场景的示例代码.

public class Sample {
    static Sample s = new Sample();
    static final int x = 5;
    static int y = 10;

    public Sample() {
        int z = x + y;
        System.out.println(z);
    }

    public static void main(String[] args) {

    }

}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,当程序运行时,输出将是5和不是10.现在让我们看一下字节码.

构造函数的字节代码如下所示:

p

ublic Sample();
   descriptor: ()V
   flags: ACC_PUBLIC
   Code:
     stack=2, locals=2, args_size=1
        0: aload_0
        1: invokespecial #24                 // Method java/lang/Object."<init>
:()V 
        4: iconst_5       ------->           // Here 5 is used directly as it is a compile time constant
        5: getstatic     #20   ------->      // Field y:I
        8: iadd
        9: istore_1
       10: getstatic     #25                 // Field java/lang/System.out:Ljav
/io/PrintStream;
       13: iload_1
       14: invokevirtual #31                 // Method java/io/PrintStream.prin
ln:(I)V
       17: return
Run Code Online (Sandbox Code Playgroud)

静态init块的字节代码:

静态的 {}; descriptor :()V flags:ACC_STATIC代码:stack = 2,locals = 0,args_size = 0 0:new#1 // class Sample 3:dup 4:invokespecial#15 // Method"":()V 7:putstatic #18 // Field s:LSample; 10:bipush 10 12:putstatic#20 // Field y:I 15:return LineNumberTable:line 3:0 line 5:10 line 1:15 LocalVariableTable:Start Length Slot Name Signature

如果仔细检查,x则不会在类的静态init中初始化.仅y被设置为静态.但是当你查看构造函数时,你会看到常量5直接被使用(iconst_5)并被压入堆栈.

现在,如果您添加以下代码main():

public static void main(String[] args) {
    System.out.println(Sample.x);
    System.out.println(Sample.y);
}
Run Code Online (Sandbox Code Playgroud)

字节代码main()将是:

   public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #25                 // Field java/lang/System.out:Ljav
a/io/PrintStream;
         3: iconst_5 -->                      // No "x" but a constant value instead of "x"
         4: invokevirtual #31                 // Method java/io/PrintStream.prin
tln:(I)V
         7: getstatic     #25                 // Field java/lang/System.out:Ljav
a/io/PrintStream;
        10: getstatic     #20                 // Field y:I --> but "y" is being fetched
        13: invokevirtual #31                 // Method java/io/PrintStream.prin
tln:(I)V
        16: return
      LineNumberTable:
        line 13: 0
        line 14: 7
        line 15: 16
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     0  args   [Ljava/lang/String;
}
Run Code Online (Sandbox Code Playgroud)

再次观察x正在被使用,iconst_5而间接y提取/引用.

  • @Prashant - Ya ..错字,与变量名混淆了..现在改了:) (2认同)
  • 在调用构造函数之前,不应该初始化所有字段吗?这就是[JLS](http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4)所说的......我认为值得一提的是为什么`BASE`是还是没有初始化. (2认同)