Статические блоки инициализации

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

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

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

250
задан Andrew Tobilko 25 November 2017 в 01:17
поделиться

6 ответов

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

{
    // 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
406
ответ дан 23 November 2019 в 02:55
поделиться

Это также полезно, когда вы на самом деле не хотите назначать значение чему-либо, например, загрузка некоторого класса только один раз во время выполнения .

Например.

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 . Также см. этот и этот ответ.

48
ответ дан 23 November 2019 в 02:55
поделиться

Если ваши статические переменные необходимо установить во время выполнения, то блок static {...} очень полезен.

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

Также полезно, когда вы хотите добавить значения к статическому члену Map , поскольку вы не можете добавить эти значения в первоначальное объявление члена.

3
ответ дан 23 November 2019 в 02:55
поделиться

Вот пример:

  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» опущено.

98
ответ дан 23 November 2019 в 02:55
поделиться

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

Например.

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());
  }
}
8
ответ дан 23 November 2019 в 02:55
поделиться

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

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

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

128
ответ дан 23 November 2019 в 02:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: