静态修饰符如何影响此代码?

2022-08-31 09:43:39

这是我的代码:

class A {
    static A obj = new A();
    static int num1;
    static int num2=0;

    private A() {
        num1++;
        num2++;
    }
    public static A getInstance() {
        return obj;
    }
}

public class Main{
    public static void main(String[] arg) {
        A obj = A.getInstance();
        System.out.println(obj.num1);
        System.out.println(obj.num2);
    }
}

输出是,但我无法理解。1 0

有人可以向我解释一下吗?


答案 1

在Java中,有两个阶段:1.识别,2.执行

  1. 识别阶段,所有静态变量都被检测并使用默认值进行初始化。

    所以现在的值为:
    A obj=null
    num1=0
    num2=0

  2. 第二阶段,执行,从上到下开始。在 Java 中,执行从第一个静态成员开始。
    在这里,您的第一个静态变量是 ,因此首先它将创建该变量的对象并调用构造函数,因此 和 的值变为 。
    然后,再次,将被执行,这使得.static A obj = new A();num1num21static int num2=0;num2 = 0;

现在,假设您的构造函数如下所示:

 private A(){
    num1++;
    num2++;
    System.out.println(obj.toString());
 }

这将抛出一个,因为仍然没有得到的引用。NullPointerExceptionobjclass A


答案 2

当应用于变量声明时,修饰符的含义是变量是类变量而不是实例变量。换句话说...只有一个变量,而且只有一个变量。staticnum1num2

(题外话:静态变量就像其他一些语言中的全局变量,除了它的名字并不是在所有地方都可见。即使它被声明为 ,非限定名也只有在当前类或超类中声明,或者使用静态导入导入时才可见。这就是区别。真正的全局变量在任何地方都可以看到,没有限定。public static

因此,当您引用 和 时,您实际上指的是静态变量其实际名称为 和 。同样,当构造函数递增 和 时,它(分别)递增相同的变量。obj.num1obj.num2A.num1A.num2num1num2

示例中令人困惑的褶皱位于类初始化中。首先默认初始化类,初始化所有静态变量,然后按照声明的静态初始值设定项(和静态初始值设定项块)在类中出现的顺序执行这些初始值设定项(和静态初始值设定项块)。在本例中,您有以下情况:

static A obj = new A();
static int num1;
static int num2=0;

它像这样发生:

  1. 静态值从其默认的初始值开始; 是和 / 都是零。A.objnullA.num1A.num2

  2. 第一个声明 () 创建 的实例,以及增量和 的构造函数。当声明完成时,并且两者都为 ,并引用新构造的实例。A.objA()AA.num1A.num2A.num1A.num21A.objA

  3. 第二个声明 () 没有初始值设定项,因此不会更改。A.num1A.num1

  4. 第三个声明 () 具有一个初始值设定项,该初始值设定项将零赋值到 。A.num2A.num2

因此,在类初始化结束时,是并且是 ...这就是您的打印报表所显示的内容。A.num11A.num20

这种令人困惑的行为实际上归结为这样一个事实,即您在静态初始化完成之前创建了一个实例,并且您使用的构造函数依赖于并修改了尚未初始化的静态。这是你应该避免在实际代码中做的事情。


推荐