Статический метод со статическим кодом по умолчанию?

Извините за плохой титул, но я нашел код, указанный ниже на 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();
    }
    ...
}