2009-11-15 16 views
6

Может кто-нибудь объяснить мне, что это такое?Java: что такое static {}?

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

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

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

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

+0

Dupe. http://stackoverflow.com/questions/335311/java-static-keyword – finnw

ответ

14

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

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


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

+1

«он запускается при первом запуске класса (и это единственный раз, когда он запускается)». - Разве он не запускается один раз за загрузчик классов, загружающий класс? Техничность я знаю, но это, возможно, стоит упомянуть. – Grundlefleck

+0

В этом случае проверка на наличие драйвера MySQL - это еще не все: создание экземпляра класса автоматически регистрирует его с помощью DriverManager. Это необходимо для ответа на URL-адреса MySQL в более поздних операциях DB connect(). –

+1

Если предложение catch создало исключение RunTimeException вместо того, чтобы просто регистрировать ошибку, загрузка класса Stuff будет прервана, и любые ссылки на него приведут к NoClassDefFoundError во время выполнения. – Henry

8

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

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

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

+0

* Статические блоки инициализатора (в отличие от конструкторов и обычных блоков инициализатора) не имеют ничего общего с инициализацией * объекта *. – Henry

1

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

final static String JDBC_DRIVER = getJdbcDriver(); 

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

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

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

class MyClass 
{ 
    final int intVar; 

    { 
    intVar = 1; 
    } 
} 

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

1

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

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

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

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

1

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

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

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

0

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

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

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

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

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

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

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

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

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

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

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

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