Статический метод со статическим кодом по умолчанию?
Извините за плохой титул, но я нашел код, указанный ниже на mkyoung.com, и задавался вопросом, что делает этот код. Является ли это способом Java для установки значения по умолчанию в переменную?
public class LanguageBean implements Serializable{
private static Map<String,Object> countries;
static{
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
}
Ответы
Ответ 1
Этот бит объявляет статическое поле:
private static Map<String,Object> countries;
Таким образом, он доступен непосредственно в классе, например. LanguageBean.countries
(или просто countries
), но только из кода внутри класса, потому что он закрыт.
Этот бит является статическим инициализатором:
static{
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
Это выполняется, когда класс загружается, прежде чем создавать какие-либо экземпляры, и действительно добавляет некоторые записи в countries
. Если существует несколько статических инициализаторов, они запускаются в порядке исходного кода. См. Блоки статического инициализатора в этот учебник.
FWIW, есть также версии для обоих экземпляров. Поле экземпляра:
private int foo;
... и инициализатор экземпляра; они выглядят немного странно, потому что они всего лишь блоки с ничего перед блоком:
{
this.foo = 42;
}
В контексте и со вторым экземпляром:
class Thing {
private int bar = 16; // An initializer on the declaration
private int foo;
// An instance initializer block
{
this.foo = 42; // Or just foo = 42;, but I prefer to be clear
}
}
Таким образом, вы можете делать то же самое для экземпляров.
Ответ 2
В принципе да, он формально называется статическим инициализатором. И за JLS-8.7 Статические инициализаторы
Статический инициализатор, объявленный в классе, выполняется, когда класс инициализируется (§12.4.2). Вместе с любыми инициализаторами полей для переменных класса (§8.3.2) статические инициализаторы могут использоваться для инициализации переменных класса класса.
Ответ 3
Они называются Статические блокировки инициализации.
Статический блок инициализации - это нормальный блок кода, заключенный в фигурные скобки {}, и которому предшествует статическое ключевое слово. Вот пример:
static {
// whatever code is needed for initialization goes here
}
Класс может иметь любое количество статических блоков инициализации, и они может появляться в любом месте тела класса. Система времени выполнения гарантирует что статические блоки инициализации вызываются в том порядке, в котором они появляются в исходном коде.
Существует альтернатива статическим блокам - вы можете написать личное статический метод:
class Whatever {
public static varType myVar = initializeClassVariable();
private static varType initializeClassVariable() {
// initialization code goes here
}
}
Преимущество частных статических методов заключается в том, что их можно повторно использовать позже, если вам нужно повторно инициализировать переменную класса.
Они вызывается всякий раз, когда класс сначала инициализируется и может использоваться для удобной инициализации полей.
Ответ 4
Статическая переменная countries
, объявленная как Map
, заполняется с помощью статического инициализатора. В Map
добавляются две записи.
static{
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
Один эффект
статический инициализатор
заключается в том, что он запускается при загрузке класса и что блок является потокобезопасным, и поэтому он используется в шаблонах проектирования, таких как singletons
и т.д., чтобы облегчить необходимость синхронизации потоков.
Подробнее см. эту тему: Безопасны ли статические инициализаторы Java?
Ответ 5
Подумайте об этом так же, как вы можете подумать о полях объектов. У вас может быть что-то вроде этого:
private final Map<String, Object> countries;
public ClassName(){
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
Это инициализирует поле члена каждый раз, когда a new ClassName()
объявляется в какое-либо "начальное" состояние. Следующее:
static{
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
... по существу делает то же самое, кроме как для статических полей. Теперь, когда класс загружен, этот статический блок вызывается и инициализирует статические поля, прежде чем их можно будет использовать, чтобы они имели некоторое "начальное" состояние. Это часто используется, когда у вас есть что-то, что не изменится (например, вы можете настроить карту, которая упрощает поиск определенных вещей) или когда вам нужно установить что-то, что может вызвать исключение, но то, что вы пытаетесь для установки действительно должен быть статичным, например:
private static KeyPairGenerator KPG;
static {
try {
KPG = KeyPairGenerator.getInstance("RSA");
KPG.initialize(2048);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.err.println("Couldn't get a Key Pair Generator...exiting");
System.exit(1);
}
}
В приведенном выше случае мне нужен только один KeyPairGenerator
для всех моих классов (при условии, что я всегда буду использовать шифрование RSA с размером ключа 2048). С помощью этого одиночного KeyPairGenerator
я могу сгенерировать несколько пар частных частных ключей. Однако создание KeyPairGenerator
вызывает исключение NoSuchAlgorithm
(чего не может быть, поскольку Java требуется для поддержки RSA с длиной ключа 2048). Поэтому я могу получить статический KeyPairGenerator
с помощью этого статического инициализатора.
Ответ 6
Он используется для создания переменной и инициализации ее во время загрузки класса (что при выполнении этапа static {}).
Как спецификация языка Java:
Статические инициализаторы (§8.7) являются блоками исполняемого кода, которые могут быть используется для инициализации класса.
И это действительно обычно используется в небольших обучающих программах для инициализации значений.
С другой стороны, они также имеют использование в "больших" программах. Вы также можете использовать его в классах Factory. В этом случае каждый конкретный продукт регистрируется в factory. При этом вам не нужно изменять класс Factory при добавлении нового конкретного продукта.
class OneProduct extends Product
{
...
static
{
ProductFactory.instance().registerProduct("ID1", new OneProduct());
}
public OneProduct createProduct()
{
return new OneProduct();
}
...
}