Java: что такое статический {}? - PullRequest
6 голосов
/ 15 ноября 2009

Может кто-нибудь объяснить мне, что является следующим?

public class Stuff
{
    static
    {
        try
        {
            Class.forName("com.mysql.jdbc.Driver");
        }
        catch ( ClassNotFoundException exception )
        {
            log.error( "ClassNotFoundException " + exception.getMessage( ) );
        }
...
}

Что делает этот статический {...}?

Я знаю о статических переменных из C ++, но это статический блок или что-то в этом роде?

Когда этот материал будет выполнен?

Ответы [ 6 ]

14 голосов
/ 15 ноября 2009

Статический блок называется статическим инициализатором класса - он запускается при первой загрузке класса (и это единственный раз, когда он запускается [сноска]).

Целью этого конкретного блока является проверка того, находится ли драйвер MySQL в пути к классам (и ошибка throw / log, если это не так).


[footnote] Статический блок запускается один раз для загрузчика классов, который загружает класс (поэтому, если у вас было несколько загрузчиков классов, отличных друг от друга (например, не делегирующих, например), он будет выполняться один раз каждый.

8 голосов
/ 15 ноября 2009

Основное использование статических блоков инициализаторов состоит в том, чтобы выполнять различные биты инициализации, которые могут не подходить внутри конструктора, так что вместе взятые конструктор и инициализаторы переводят вновь созданный объект в состояние, полностью совместимое для использования. *

В отличие от конструкторов, например, статические инициализаторы не наследуются и выполняются только один раз, когда класс загружается и инициализируется JRE. В приведенном выше примере переменная класса foo будет иметь значение 998877 после завершения инициализации.

Обратите внимание, что статические инициализаторы выполняются в том порядке, в котором они появляются в исходном файле в текстовом виде. Кроме того, существует ряд ограничений на то, что вы не можете делать внутри одного из этих блоков, например, не использовать проверенные исключения, не использовать оператор return или ключевые слова this и super.

1 голос
/ 02 июня 2012

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

Когда у нас есть статические переменные и статический блок, то сначала инициализируются статические переменные, а затем блок.

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

1 голос
/ 15 ноября 2009

Статический блок инициализатора выполняется всякий раз, когда класс должен быть загружен в первый раз. Это может произойти, если что-то на более высоком уровне впервые делает Class#forName("yourpackage.YourClass") или new YourClass() в рассматриваемом классе.

По совпадению, приличные драйверы JDBC также имеют нечто подобное внутри. Именно они регистрируются в DriverManager с использованием статического блока инициализации:

static {
    DriverManager.registerDriver(new ThisDriver());
}

чтобы каждый раз, когда вы делаете Class.forName("somepackage.ThisDriver"), вы эффективно регистрировали драйвер в DriverManager, чтобы впоследствии вы могли подключиться к нему.

1 голос
/ 15 ноября 2009

Хочу добавить, что статические переменные и статические инициализаторы выполняются в порядке появления во время загрузки класса. Таким образом, если ваш статический инициализатор использует некоторую статическую переменную, он должен быть инициализирован перед определенным статическим блоком, например

final static String JDBC_DRIVER = getJdbcDriver( );

static
{
  try
  {
    Class.forName(JDBC_DRIVER);
  }
  catch ( ClassNotFoundException exception )
  {
    log.error( "ClassNotFoundException " + exception.getMessage( ) );
  }
}

В этом примере getJdbcDriver будет выполнено перед статическим инициализатором. Кроме того, в классе может быть более 1 статического инициализатора. Еще раз они выполняются в порядке появления.

Я также хочу упомянуть о существовании здесь инициализаторов экземпляров, поскольку они удивляют, когда их видят впервые. Они выглядят как блок кода внутри тела класса, вот так.

class MyClass
{
  final int intVar;

  {
    intVar = 1;
  }
}

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

0 голосов
/ 01 июня 2016

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

  • - нормальный блок кода

  • заключено в фигурные скобки {}

  • ему предшествует статическое ключевое слово

    class Foo {
        static {
            // initialization code goes here:
            doSomething();
        }
    }
    
  • класс может иметь любое количество статических блоков инициализации

  • они могут появляться в любом месте тела класса

  • они называются в порядке появления в коде

Есть альтернатива статическим блокам инициализации:

  • написать приватный статический метод
  • и присвоить его статической переменной класса

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

class Foo {
    public static int myVar = initializeClassVariable();

    private static int initializeClassVariable() {
        // initialization code goes here:
        int v = 255;
        return v;
    }
}
...