Насколько я понял, что "статический блок инициализации" привык к установленным значениям статического поля, если это не может быть сделано в одной строке.
Но я не понимаю, почему нам нужен специальный блок для этого. Например, мы объявляем поле как статичное (без присвоения значения). И затем запишите несколько строк кода, которые генерируют и присваивают значение вышеупомянутому заявленному статическому полю.
Почему делают нам нужно это строки в специальном блоке как: static {...}
?
Нестатический блок :
{
// 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
Это также полезно, когда вы на самом деле не хотите назначать значение чему-либо, например, загрузка некоторого класса только один раз во время выполнения .
Например.
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.
тогда полезен инициализатор static
здесь. Здесь вы можете обработать исключение.
Другой пример - впоследствии делать то, что невозможно сделать во время присвоения:
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 сам также использует инициализатор static
для зарегистрируйтесь в DriverManager
. Также см. этот и этот ответ.
Если ваши статические переменные необходимо установить во время выполнения, то блок 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» опущено.
Вы можете выполнить биты кода один раз для класса, прежде чем объект будет построен в статических блоках.
Например.
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());
}
}
Если бы они не были в статическом блоке инициализации, где бы они были? Как бы вы объявили переменную, которая должна была быть локальной только для целей инициализации, и отличить ее от поля? Например, как вы хотите написать:
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;
}
}
Если бы первый
и второй
не были в блоке, они выглядели бы как поля. Если бы они находились в блоке без static
перед ним, это будет считаться блоком инициализации экземпляра, а не статическим блоком инициализации, поэтому он будет выполняться один раз на каждый созданный экземпляр, а не чем один раз всего.
Теперь в этом конкретном случае вы могли бы вместо этого использовать статический метод:
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;
}
}
... но это не работает, когда есть несколько переменных, которые вы хотите назначить в одном блоке, или ни одной (например, если вы просто хотите что-то записать - или, может быть, инициализировать собственную библиотеку).