Насколько я понял, «статический блок инициализации» используется для установки значений статического поля, если это невозможно сделать в одной строке.
Но я не понимаю, зачем нам для этого нужен специальный блок. Например, мы объявляем поле как статическое (без присвоения значения). А затем напишите несколько строк кода, которые генерируют и присваивают значение объявленному выше статическому полю.
Зачем нам нужны эти строки в специальном блоке вроде static {...}
:?
{...}
противstatic {...}
. (в этом случае Джон Скит определенно ответил на ваш вопрос лучше)Ответы:
Нестатический блок:
Вызывается каждый раз, когда создается экземпляр класса. Статический блок только вызывается один раз , когда сам класс инициализируется, независимо от того , сколько объектов этого типа вы создаете.
Пример:
Это печатает:
источник
Если бы они не были в статическом блоке инициализации, где бы они были? Как бы вы объявили переменную, которая должна была быть только локальной для целей инициализации, и отличали бы ее от поля? Например, как бы вы хотели написать:
Если бы
first
иsecond
не было в блоке, они бы выглядели как поля. Если бы они находились в блоке безstatic
него, это считалось бы блоком инициализации экземпляра, а не статическим блоком инициализации, поэтому он будет выполняться один раз для каждого созданного экземпляра, а не один раз в общей сложности.Теперь в этом конкретном случае вы можете использовать вместо этого статический метод:
... но это не работает, когда есть несколько переменных, которые вы хотите назначить в одном блоке, или ни одной (например, если вы просто хотите что-то записать - или, может быть, инициализировать нативную библиотеку).
источник
private static int widgets = 0; static{widgets = 2;}
private static int widgets = 0; static{widgets = 2;}
выяснилось, что назначение «=» происходит по порядку, что означает, что «=», поставленное первым, будет назначено первым. В приведенном выше примере значение «виджетов» будет равно 2. (PS не знал, что комментарии можно редактировать только через 5 минут ...)Вот пример:
Код в «статических» разделах будет выполняться во время загрузки класса до того, как будут созданы какие-либо экземпляры класса (и до того, как какие-либо статические методы будут вызваны из других источников). Таким образом, вы можете быть уверены, что все ресурсы класса готовы к использованию.
Также возможно иметь нестатические блоки инициализатора. Они действуют как расширения для набора методов конструктора, определенных для класса. Они выглядят так же, как статические блоки инициализатора, за исключением того, что ключевое слово «static» не указано.
источник
Это также полезно, когда вы на самом деле не хотите присваивать значение чему-либо, например, загружать некоторый класс только один раз во время выполнения.
Например
Эй, есть еще одно преимущество, вы можете использовать его для обработки исключений. Представьте, что
getStuff()
здесь выдается объект,Exception
который действительно принадлежит блоку catch:тогда здесь можно использовать
static
инициализатор. Вы можете обработать исключение там.Другой пример - сделать что-то потом, чего нельзя сделать во время присваивания:
Чтобы вернуться к примеру с драйвером JDBC, любой приличный драйвер JDBC сам также использует
static
инициализатор для регистрации себя вDriverManager
. Также посмотрите этот и этот ответ.источник
Я бы сказал,
static block
это просто синтаксический сахар. Вы ничего не можете сделать сstatic
блоком, и не с чем-либо еще.Чтобы повторно использовать некоторые примеры, размещенные здесь.
Этот кусок кода может быть переписан без использования
static
инициализатора.Способ № 1: с
static
Способ № 2: без
static
источник
Есть несколько фактических причин, по которым он необходим:
static final
члены, инициализация которых может вызвать исключениеstatic final
членов с вычисленными значениямиЛюди склонны использовать
static {}
блоки в качестве удобного способа инициализации вещей, от которых зависит класс, также во время выполнения, таких как обеспечение загрузки определенного класса (например, драйверов JDBC). Это может быть сделано другими способами; однако две вещи, которые я упомянул выше, могут быть выполнены только с помощью конструкции, подобнойstatic {}
блоку.источник
Вы можете выполнить биты кода один раз для класса, прежде чем объект будет создан в статических блоках.
Например
источник
Распространено заблуждение, что статический блок имеет доступ только к статическим полям. Для этого я хотел бы показать ниже фрагмент кода, который я довольно часто использую в реальных проектах (частично скопированный из другого ответа в несколько ином контексте):
Здесь инициализатор используется для поддержки index (
ALIAS_MAP
), чтобы отобразить набор псевдонимов обратно в исходный тип перечисления. Он предназначен как расширение встроенного метода valueOf, предоставляемого самимEnum
собой.Как видите, статический инициализатор получает доступ даже к
private
полюaliases
. Важно понимать, чтоstatic
блок уже имеет доступ кEnum
экземплярам значений (напримерENGLISH
). Это потому, что порядок инициализации и выполнения в случаеEnum
типов так же, как если быstatic private
поля были инициализированы с экземплярами доstatic
вызова блоков:Enum
константы , которые являются неявными полями статических. Это требует, чтобы конструктор Enum и блоки экземпляра, а также инициализация экземпляра выполнялись первыми.static
блок и инициализация статических полей в порядке появления.Эта нестандартная инициализация (конструктор перед
static
блоком) очень важна. Это также происходит, когда мы инициализируем статические поля с экземплярами, аналогичными Singleton (сделаны упрощения):То, что мы видим, это следующий вывод:
Понятно, что статическая инициализация на самом деле может происходить до конструктора и даже после:
Простой доступ к Foo в методе main приводит к загрузке класса и запуску статической инициализации. Но как часть статической инициализации мы снова вызываем конструкторы для статических полей, после чего она возобновляет статическую инициализацию и завершает конструктор, вызываемый из основного метода. Довольно сложная ситуация, для которой я надеюсь, что при нормальном кодировании нам не пришлось бы иметь дело с.
Подробнее об этом см. Книгу « Эффективная Java ».
источник
aliases
не означает, что статический блок может получить доступ к нестатическим членам.aliases
Доступ осуществляется черезLanguage
значения, возвращаемые методом / static /values()
. Как вы упомянули, тот факт, что переменные перечисления уже доступны в тот момент, является необычным битом - нестатические члены обычных классов не будут доступны в этой ситуации.class Foo { static final Foo Inst1; static final Foo Inst2; static{ Inst1 = new Foo("Inst1"); Inst2 = new Foo("Inst2"); } static { System.out.println("Inst1: " + Inst1.member); System.out.println("Inst2: " + Inst2.member); } private final String member; private Foo(String member){ this.member = member; } }
Приведенный выше код ничем не отличается от примера enum и по-прежнему разрешает доступ к переменной экземпляра внутри статического блокаEnum
. Это лучший способ гарантировать, что мы указываем на единичные случаи »- смотрите здесь . И что касается вас, я сделал несколько обновлений.Если ваши статические переменные должны быть установлены во время выполнения,
static {...}
блок очень полезен.Например, если вам нужно установить для статического члена значение, которое хранится в файле конфигурации или базе данных.
Также полезно, когда вы хотите добавить значения к статическому
Map
члену, поскольку вы не можете добавить эти значения в первоначальном объявлении члена.источник
Таким образом, у вас есть статическое поле (оно также называется «переменная класса», потому что оно принадлежит классу, а не экземпляру класса; другими словами, оно связано с классом, а не с каким-либо объектом), и вы хотите его инициализировать. Поэтому, если вы НЕ хотите создавать экземпляр этого класса и хотите манипулировать этим статическим полем, вы можете сделать это тремя способами:
1- Просто инициализируйте его, когда объявляете переменную:
2- иметь статический блок инициализации:
3. Иметь метод класса (статический метод), который обращается к переменной класса и инициализирует ее: это альтернатива вышеуказанному статическому блоку; Вы можете написать приватный статический метод:
Теперь, почему бы вам использовать статический блок инициализации вместо статических методов?
Это действительно зависит от того, что вам нужно в вашей программе. Но вы должны знать, что статический инициализирующий блок вызывается один раз, и единственное преимущество метода класса заключается в том, что они могут быть повторно использованы позже, если вам нужно повторно инициализировать переменную класса.
скажем, у вас есть сложный массив в вашей программе. Вы инициализировать его (используя для цикла, например) , а затем значения в этом массиве будет меняться в течение всей программы , но потом в какой - то момент вы хотите реинициализировать (вернуться к исходному значению). В этом случае вы можете вызвать закрытый статический метод. Если в вашей программе не требуется повторная инициализация значений, вы можете просто использовать статический блок и не нуждаться в статическом методе, так как вы не собираетесь использовать его позже в программе.
Примечание: статические блоки вызываются в порядке их появления в коде.
Пример 1:
Пример 2:
источник
В качестве дополнительного, как сказал @Pointy
Предполагается добавить
System.loadLibrary("I_am_native_library")
в статический блок.Это гарантирует, что ни один нативный метод не будет вызван до загрузки соответствующей библиотеки в память.
Согласно loadLibrary от оракула :
Так что совершенно неожиданно размещение System.loadLibrary не используется, чтобы избежать многократной загрузки библиотеки.
источник
Сначала вы должны понять, что сами классы вашего приложения создаются для
java.class.Class
объектов во время выполнения. Это когда ваши статические блоки запускаются. Таким образом, вы можете сделать это:и это выведет «myInt is 1» на консоль. Обратите внимание, что я не создал ни одного класса.
источник
источник
Статический блок используется для любой технологии для динамической инициализации члена статических данных, или мы можем сказать, что для динамической инициализации статического члена данных используется статический блок. Потому что для инициализации не статического члена данных у нас есть конструктор, но у нас нет любое место, где мы можем динамически инициализировать статический член данных
Теперь мой static int x будет динамически инициализироваться ..Bcoz, когда компилятор перейдет в Solution.x, он загрузит класс решения и загрузку статического блока во время загрузки класса .. Так что мы можем динамически инициализировать этот статический член данных ..
}
источник