关于静态初始化块(static initialization block)执行先后顺序的一个怪异现象

时间:2022-05-31 00:43:45
Core Java上说,当类被调用时,该类的静态初始化块会被加载有且仅有一次,并且是在该类中所有其他语句执行之前加载,可是在下面这段代码中,有两个静态块,分别是在Scanner语句之前和之后加载的,为什么会这样呢?这样不是和书上说的矛盾了么?按书上说的,应该是两个块同时在其他语句执行之前加载的啊,请高手们指点。。。


import java.util.*;

class Test
{
  public static void main(String[] args)
  {
    System.out.println("Test");
    System.out.println(T.num);
  }  
}

class T
{
  static 
  {
    System.out.println("之前加载");
  }
  static int n = new Scanner(System.in).nextInt();
  public static final int num = n;
  static 
  {
    System.out.println("之后加载");
  }
}

控制台输入如下:
Test
之前加载
[BLUEJ Input Box]<--询问输入的对话框
之后加载
12

8 个解决方案

#1


是因为你的n,num是static

#2


“该类的静态初始化块会被加载有且仅有一次,并且是在该类中所有其他语句执行之前加载“
不仅静态块如此,静态变量也是。而且它们的初始化顺序由jvm决定(有可能是由上倒下);

#3


没有啊,是这样的啊,他的运行顺序是按照你想的这样初始化的,
static 
  {
    System.out.println("之前加载");
  }
  static int n = new Scanner(System.in).nextInt();
  public static final int num = n;
  static 
  {
    System.out.println("之后加载");
  }
当程序运行到System.out.println(T.num);这句时,那么就进行对类T的加载--》连接--》初始化,
它运行完第一个static静态初始化块之后,发现第二条语句是一个阻塞式的语句,需要你输入一个数之后程序才能继续运行,那么当你输入12后按回车,程序马上执行每二个静态初始化块,最后才执行把 n的值赋值给常量num,那么最后才调用到System.out.println(T.num);这条语句打印出常量num的值

#4


果然啊!把变量修改成非静态的,执行顺序就跟书上说的一样了!看来csdn果然跟马士兵老师说的一样,高手如云!

import java.util.*;

class Test
{
  public static void main(String[] args)
  {
    System.out.println("Test");
    System.out.println(new T().num);
  }  
}

class T
{
  static 
  {
    System.out.println("之前加载");
  }
  int n = new Scanner(System.in).nextInt();
  final int num = n;
  static 
  {
    System.out.println("之后加载");
  }
}

修改后的运行结果:
Test
之前加载
之后加载
[BLUEJ Input Box]
12

#5


引用 3 楼 xinji84 的回复:
没有啊,是这样的啊,他的运行顺序是按照你想的这样初始化的, 


明白了,当主程序执行到需要加载其他的类的时候,该类中加载的顺序是:
1.从上倒下:静态块,静态变量,静态常量(排名不分先后)
2.跳回原程序流程,
3.将静态常量的值以形参的形式拷贝给println(...)方法的实参
4.执行打印,保存在栈中的方法参数被销毁

#6


オブジェクト指向プログラミング

OOP?

#7


引用楼主 bigbro001 的帖子:
Core Java上说,当类被调用时,该类的静态初始化块会被加载有且仅有一次,并且是在该类中所有其他语句执行之前加载,可是在下面这段代码中,有两个静态块,分别是在Scanner语句之前和之后加载的,为什么会这样呢?这样不是和书上说的矛盾了么?按书上说的,应该是两个块同时在其他语句执行之前加载的啊,请高手们指点。。。 


Java code
import java.util.*;

class Test
{
  public static void main(String[] args)

答: 记住一句话就行了:static初始化块与static型变量,是按照你 定义的先后次序来执行的(无论有多少个static初始化块和多少个static型变量).就行了.

#8


引用 6 楼 For_suzhen 的回复:
オブジェクト指向プログラミング 
OOP?

For_suzhenさんは日本語を話ますか?

#1


是因为你的n,num是static

#2


“该类的静态初始化块会被加载有且仅有一次,并且是在该类中所有其他语句执行之前加载“
不仅静态块如此,静态变量也是。而且它们的初始化顺序由jvm决定(有可能是由上倒下);

#3


没有啊,是这样的啊,他的运行顺序是按照你想的这样初始化的,
static 
  {
    System.out.println("之前加载");
  }
  static int n = new Scanner(System.in).nextInt();
  public static final int num = n;
  static 
  {
    System.out.println("之后加载");
  }
当程序运行到System.out.println(T.num);这句时,那么就进行对类T的加载--》连接--》初始化,
它运行完第一个static静态初始化块之后,发现第二条语句是一个阻塞式的语句,需要你输入一个数之后程序才能继续运行,那么当你输入12后按回车,程序马上执行每二个静态初始化块,最后才执行把 n的值赋值给常量num,那么最后才调用到System.out.println(T.num);这条语句打印出常量num的值

#4


果然啊!把变量修改成非静态的,执行顺序就跟书上说的一样了!看来csdn果然跟马士兵老师说的一样,高手如云!

import java.util.*;

class Test
{
  public static void main(String[] args)
  {
    System.out.println("Test");
    System.out.println(new T().num);
  }  
}

class T
{
  static 
  {
    System.out.println("之前加载");
  }
  int n = new Scanner(System.in).nextInt();
  final int num = n;
  static 
  {
    System.out.println("之后加载");
  }
}

修改后的运行结果:
Test
之前加载
之后加载
[BLUEJ Input Box]
12

#5


引用 3 楼 xinji84 的回复:
没有啊,是这样的啊,他的运行顺序是按照你想的这样初始化的, 


明白了,当主程序执行到需要加载其他的类的时候,该类中加载的顺序是:
1.从上倒下:静态块,静态变量,静态常量(排名不分先后)
2.跳回原程序流程,
3.将静态常量的值以形参的形式拷贝给println(...)方法的实参
4.执行打印,保存在栈中的方法参数被销毁

#6


オブジェクト指向プログラミング

OOP?

#7


引用楼主 bigbro001 的帖子:
Core Java上说,当类被调用时,该类的静态初始化块会被加载有且仅有一次,并且是在该类中所有其他语句执行之前加载,可是在下面这段代码中,有两个静态块,分别是在Scanner语句之前和之后加载的,为什么会这样呢?这样不是和书上说的矛盾了么?按书上说的,应该是两个块同时在其他语句执行之前加载的啊,请高手们指点。。。 


Java code
import java.util.*;

class Test
{
  public static void main(String[] args)

答: 记住一句话就行了:static初始化块与static型变量,是按照你 定义的先后次序来执行的(无论有多少个static初始化块和多少个static型变量).就行了.

#8


引用 6 楼 For_suzhen 的回复:
オブジェクト指向プログラミング 
OOP?

For_suzhenさんは日本語を話ますか?