Вопрос-ответ

Static Initialization Blocks

Блоки статической инициализации

Насколько я понял, "блок статической инициализации" используется для установки значений статического поля, если это невозможно сделать в одной строке.

Но я не понимаю, зачем нам для этого нужен специальный блок. Например, мы объявляем поле как статическое (без присвоения значения). А затем напишите несколько строк кода, которые генерируют и присваивают значение вышеуказанному статическому полю.

Зачем нам нужны эти строки в специальном блоке типа: static {...}?

Переведено автоматически
Ответ 1

Нестатический блок:

{
// Do Something...
}

Вызывается каждый раз, когда создается экземпляр класса. Статический блок вызывается только один раз, когда инициализируется сам класс, независимо от того, сколько объектов этого типа вы создаете.

Пример:

public class Test {

static{
System.out.println("Static");
}

{
System.out.println("Non-static block");
}

public static void main(String[] args) {
Test t = new Test();
Test t2 = new Test();
}
}

Это выводит:

Static
Non-static block
Non-static block
Ответ 2

Если бы их не было в блоке статической инициализации, где бы они были? Как бы вы объявили переменную, которая должна быть локальной только для целей инициализации, и отличили ее от поля? Например, как бы вы хотели написать:

public class Foo {
private static final int widgets;

static {
int first = Widgets.getFirstCount();
int second = Widgets.getSecondCount();
// Imagine more complex logic here which really used first/second
widgets = first + second;
}
}

Если бы first и second не были в блоке, они выглядели бы как поля. Если бы они были в блоке без static перед ним, это считалось бы блоком инициализации экземпляра, а не блоком статической инициализации, поэтому он выполнялся бы один раз на созданный экземпляр, а не один раз в целом.

Now in this particular case, you could use a static method instead:

public class Foo {
private static final int widgets = getWidgets();

static int getWidgets() {
int first = Widgets.getFirstCount();
int second = Widgets.getSecondCount();
// Imagine more complex logic here which really used first/second
return first + second;
}
}

... but that doesn't work when there are multiple variables you wish to assign within the same block, or none (e.g. if you just want to log something - or maybe initialize a native library).

Ответ 3

Here's an example:

  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");
}

The code in the "static" section(s) will be executed at class load time, before any instances of the class are constructed (and before any static methods are called from elsewhere). That way you can make sure that the class resources are all ready to use.

It's also possible to have non-static initializer blocks. Those act like extensions to the set of constructor methods defined for the class. They look just like static initializer blocks, except the keyword "static" is left off.

Ответ 4

It's also useful when you actually don't want to assign the value to anything, such as loading some class only once during runtime.

E.g.

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

Hey, there's another benefit, you can use it to handle exceptions. Imagine that getStuff() here throws an Exception which really belongs in a catch block:

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

then a static initializer is useful here. You can handle the exception there.

Another example is to do stuff afterwards which can't be done during assigning:

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);
}
}

To come back to the JDBC driver example, any decent JDBC driver itself also makes use of the static initializer to register itself in the DriverManager. Also see this and this answer.

java