Эта конструкция называется
блоком статической инициализации. Есть ещё точно такой же
блок динамической инициализации, только без ключевого слова static.
Блоки инициализации нужны для задания начальных значений полям класса.
class Initable2 {
static int staticNonFinal;
public static void main(String[] args) {
System.out.println(staticNonFinal);
}
}
Данный пример выведет ноль, хотя переменной staticNonFinal не присваивалось никакое значение. Java гарантирует, что любые поля класса будут проинициализированы "нулевым" значением. То есть компилятор неявно вставляет в класс блок статической инициализации, в котором переменной staticNonFinal присваивается ноль.
class Initable2 {
static int staticNonFinal;
// Вот этот блок будет добавлен к
// вашему классу во время компиляции.
static {
staticNonFinal = 0;
}
public static void main(String[] args) {
System.out.println(staticNonFinal);
}
}
Разумеется, вы можете инициализировать переменные своими значениями:
class Initable2 {
static int staticNonFinal = 42;
static String a = "hello";
static Cache<String, Integer> b = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
И тогда компилятор в блоке инициализации будет подставлять ваши значения вместо нулей:
class Initable2 {
static int staticNonFinal;
static String a;
static Cache<String, Integer> b;
static {
staticNonFinal = 42;
a = "hello";
b = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
}
А если вашей переменной требуется какая-то сложная инициализация, которую одной строкой не представить (как в примере с Cache), то тогда вам придется написать блок инициализации явным образом вручную:
class Initable2 {
static int staticNonFinal = 42;
static Map<Integer, String> statusCodes = new HashMap<>();
static {
statusCodes.put(200, "OK");
statusCodes.put(404, "Not Found");
statusCodes.put(418, "I'm a teapot");
}
}
И тогда компилятор сгенерирует вам такой код:
class Initable2 {
static int staticNonFinal;
static Map<Integer, String> statusCodes;
static {
staticNonFinal = 42;
statusCodes = new HashMap<>()
statusCodes.put(200, "OK");
statusCodes.put(404, "Not Found");
statusCodes.put(418, "I'm a teapot");
}
}
Точно таким же способом инициализируются и нестатические поля при помощи блока
динамической инициализации (перед таким блоком отсутствует ключевое слово static и выглядит как просто фигурные скобки в теле класса). Каждый раз при создании объекта класса сначала выполняется блок динамической инициализации, а затем конструктор. Именно в таком порядке. Блок статической инициализации выполняется один раз при загрузке класса в память.
Блоки динамической инициализации редко используются программистами, так как проще всего сделать "инициализацию" в конструкторе (в кавычках, потому что формальная инициализация уже была выполнена перед запуском конструктора и конструктор просто переписывает уже инициализированное значение своим, поэтому более точным термином здесь будет
переприсваивание). Но блоки статической инициализации используются довольно часто, так как статических конструкторов не существует.
Вот эти все блоки инициализации были придуманы создателями языка java чтобы исключить целый класс лютых ошибок, связанных с доступом к неинициализированным переменным, характерный для языков си и си++.