有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么java静态变量没有更新?

我有一个名为Color的类,其中有三个静态对象(用同一个类本身实例化)和一个int类型(称为I)变量。当我运行这个类时,“I”变量在构造函数中是递增的,但它没有在内存中持久化,请在下面解释这个代码

package test;
public class Color
{
     public static  Color RED = new Color();
     public static final Color BLUE = new Color();
     public static final Color GREEN = new Color();
     static int i=0;

     Color(){
         System.out.println("Incrementing 'i'  here  "+(++i));
     }

     public static void main(String[] args) {
         System.out.println("The 'i' variable is not incremented here, it still shows '0' ,  'i' is: "+ Color.i );  // line 14 
        Color x = new Color();
        System.out.println(x.i);
    }
}

结果如下:

Incrementing 'i'  here  1
Incrementing 'i'  here  2
Incrementing 'i'  here  3
The 'i' variable is not incremented here, it still shows '0' ,  'i' is: 0
Incrementing 'i'  here  1
1

共 (2) 个答案

  1. # 1 楼答案

    加载并链接一个类时,它的static字段都初始化为默认值。完成后,静态字段初始值设定项将按照它们在文件中出现的顺序执行,从而完成类的初始化。所有这些都发生在该类中定义的任何代码执行之前。所以这里发生的事情是:

    1. REDGREENBLUEi被初始化为它们的默认值(null用于Color字段,0用于i)。请注意,这与任何初始值设定项无关
    2. 执行字段REDRED = new Color())的初始值设定项。作为副作用,i增加到1
    3. 执行字段BLUE的初始值设定项,并且i增加到2
    4. 执行字段GREEN的初始值设定项,并且i增加到3
    5. 执行static字段i的初始值设定项,并且i被赋值为0
    6. 执行main()方法,并在main()开始执行时生成与i为0一致的结果

    你可以在Chapter 12 of the Java Language Specification (JLS)Chapter 5 of the Java Virtual Machine Specification中阅读这一切的血腥细节

    只需将i的声明移到Color字段之前,即可获得预期的输出:

     static int i=0;
     public static  Color RED = new Color();
     public static final Color BLUE = new Color();
     public static final Color GREEN = new Color();
    

    然后输出将是:

    Incrementing 'i' here 1
    Incrementing 'i' here 2
    Incrementing 'i' here 3
    The 'i' variable is not incremented here, it still shows '0' , 'i' is: 3
    Incrementing 'i' here 4
    4

    注意final修饰符对这里的初始化顺序没有影响,因为GREENBLUE根据JLS中该术语的定义不是“常量变量”。常量变量(一个不幸的词对)是一个原语或String变量,它既是声明的final又初始化为常量表达式。在这种情况下,new Color()不是常量表达式,Color不是常量变量的合适类型。例如,见§4.12.4 of the JLS

  2. # 2 楼答案

    类初始化从上到下进行。当我们初始化颜色时,我们会创建一种新的颜色。为了创建新颜色,我们还必须初始化颜色。这叫做递归初始化,系统所做的只是忽略递归初始化并执行new Color()。该类初始值设定项按以下顺序自上而下执行

    1. public static Color RED = new Color();这将静态变量i设置为1

    2. public static final Color BLUE = new Color();这将静态变量i增加到2

    3. public static final Color GREEN = new Color();这将静态变量i增加到3

    4. static int i=0;这将静态变量i设置回零

    现在当主线程运行时。它将静态变量设置为0,并递增为1

    作为反例,尝试将static int i=0替换为static Integer i=new Integer(0).。这将抛出一个NullPointerException。这是因为在类初始化时,当public static Color RED = new Color();执行时,它会将i视为null,因为那时我还没有初始化,导致NullPointerException