13
public class Hello {
        public static final Hello h = new Hello();
        static int i = 5;
        int j  = i;

        private void print() {
            System.out.println(i+" , "+j);

        }
        public static void main(String[] args) {

            h.print();
        }

    }

此代码输出为 5 , 0。如果原因是类中首先静态加载并且 i 已初始化而 j 未初始化。但如果我也从 i 中删除静态

public class Hello {
        public static final Hello h = new Hello();
        int i = 5;
        int j  = i;

        private void print() {
            System.out.println(i+" , "+j);

        }
        public static void main(String[] args) {

            h.print();
        }

    }

现在为什么输出是 5,5。然后当 i 和 j 被初始化时。请解释原因。

4

7 回答 7

16

静态块按顺序执行。

您首先创建一个 Hello 对象,此时i = 0尚未设置它。

只有在这之后i = 5

您必须从上到下阅读静态语句。

于 2013-06-21T11:26:08.400 回答
5

非静态变量i,并在创建对象j时初始化:Hello

public static final Hello h = new Hello();

对于问题的第一部分,彼得给了你一个答案。让我补充一下。如果您更改了静态变量的顺序:

static int i = 5;
public static final Hello h = new Hello();
int j  = i;

它会打印5, 5而不是5, 0

于 2013-06-21T11:26:24.157 回答
2

尝试交换public static final Hello h = new Hello();static int i = 5;线。您首先初始化hello对象(when i = 0, uninitialized),然后初始化i. 初始化第i一个以获得预期的行为。

于 2013-06-21T11:30:35.257 回答
2

这是您的第一个示例中发生的情况:

  • 静态内存初始化为0。此时Hello.i等于0。
  • Hello.h被实例化:
    • Hello.h.j初始化为Hello.i的当前值,即 0。
  • Hello.i初始化为 5。

另一方面,在您的第二个示例中:

  • Hello.h被实例化:
    • Hello.h.i初始化为 5。
    • Hello.h.j初始化为Hello.h.i的当前值,即 5。
于 2013-06-21T11:39:46.517 回答
1

Peter Lawrey 的回答是正确的,您的困惑可能来自这样一个事实,即所有内容都在一个类中并且名称类似所以我想给您另一种方式来可视化您在做什么,因此您的代码在逻辑上等同于以下代码:

public class Program {

    public static Hello h = new Hello();

        public static void main(String [] args) {
            h.i = 5;
            h.print();
        }
    }

    class Hello {

        public static int i = 0;
        private int j = i;

        public void print() {
            System.out.println(i+", "+j);
        }
    }
于 2013-06-21T13:53:59.300 回答
0

Java 在类加载时进行静态初始化。所以

public static final Hello h = new Hello();

在加载Hello类时创建一个i = 5且默认值为j的对象。

如果您将变量ij都设为非静态成员,则两者都将具有静态对象 h的默认值。

如果您在 main 方法中创建一个新对象

Hello helloObj = new Hello();

它会给你你想要的结果。

于 2013-06-21T11:28:33.587 回答
0

来自 oracle 规范的文档

类中声明的静态初始化程序在类初始化时执行(第 12.4.2 节)。与类变量的任何字段初始化器(第 8.3.2 节)一起,静态初始化器可用于初始化类的类变量。

于 2013-06-21T11:39:51.587 回答