据我所知,“静态初始化块”是用来设置静态字段的值,如果它不能在一行中完成。

但我不明白为什么我们需要一种特殊的积木。例如,我们将一个字段声明为静态(没有赋值)。然后写几行代码,生成并赋值给上面声明的静态字段。

为什么我们需要这些行在一个特殊的块,如:static{…}?


当前回答

在静态块中构造对象之前,可以为一个类执行一次代码。

E.g.

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}

其他回答

如果你的静态变量需要在运行时设置,那么一个静态{…} block非常有用。

例如,如果您需要将static成员设置为存储在配置文件或数据库中的值。

当您想要向静态Map成员添加值时也很有用,因为您不能在初始成员声明中添加这些值。

这里有一个例子:

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

“静态”部分中的代码将在类加载时执行,在构造类的任何实例之前(并且在从其他地方调用任何静态方法之前)。这样可以确保类资源都准备好使用了。

也可以使用非静态初始化块。它们的作用类似于为该类定义的构造函数方法集的扩展。它们看起来就像静态初始化块,除了关键字“static”被省略了。

作为补充,就像@Pointy说的

“静态”部分中的代码将在类加载时执行 时间,在构造类的任何实例之前(以及在 任何静态方法都从其他地方调用)。

它应该将System.loadLibrary("I_am_native_library")添加到静态块中。

static{
    System.loadLibrary("I_am_a_library");
}

它将保证在相关库加载到内存之前不调用本机方法。

根据oracle的loadLibrary:

如果使用相同的库名多次调用此方法, 第二次和随后的调用将被忽略。

所以很意外地,把系统。不使用loadLibrary以避免库被多次加载。

当您实际上不想将值赋给任何东西时,例如在运行时只加载某个类一次时,它也很有用。

E.g.

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

嘿,还有一个好处,你可以用它来处理异常。想象一下getStuff()在这里抛出了一个异常,该异常实际上属于一个catch块:

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

那么静态初始化式在这里很有用。您可以在那里处理异常。

另一个例子是事后做一些在分配过程中不能做的事情:

private static Properties config = new Properties();

static {
    try { 
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

回到JDBC驱动程序示例,任何像样的JDBC驱动程序本身也使用静态初始化器在DriverManager中注册自己。还有这个和这个答案。

在静态块中构造对象之前,可以为一个类执行一次代码。

E.g.

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}