Почему java Instance инициализаторы?

В чем смысл "инициализаторов экземпляра" на Java?
Разве мы не можем просто поместить этот блок кода в начало конструктора?

Ответ 1

Я использую их очень часто, как правило, для создания и заполнения Карты в одном выражении (вместо использования уродливого статического блока):

private static final Map<String, String> CODES = new HashMap<String, String>() {
    {
        put("A", "Alpha");
        put("B", "Bravo");
    }
};

Одно интересное и полезное приукрашивание - создание немодифицируемой карты в одном утверждении:

private static final Map<String, String> CODES = 
    Collections.unmodifiableMap(new HashMap<String, String>() {
    {
        put("A", "Alpha");
        put("B", "Bravo");
    }
});

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

И еще один совет: не бойтесь создавать методы, которые упрощают ваш блок экземпляра:

private static final Map<String, String> CODES = new HashMap<String, String>() {
    {
        put("Alpha");
        put("Bravo");
    }

    void put(String code) {
        put(code.substring(0, 1), code);
    }
};

Ответ 2

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

(Если вы только начинаете с программирования, возможно, вы не знали, что можно создать много конструкторов для одного и того же класса (если они принимают разные параметры), это называется перегрузкой конструктора. только один конструктор, то инициализатор экземпляра действительно не очень полезен (Edit: Если вы не злоупотребляете им в творческой моде, как показано в других ответах).

Ответ 3

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

List<String> mylist = new ArrayList<String>(){{add("a"); add("b"); add("c");}};

Здесь вы можете инициализировать объект, даже если вы ничего не можете добавить к конструктору (потому что класс анонимный).

Ответ 4

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

import java.util.Scanner;

public  class InstanceInitializer {
    int x;
    {
        try {
            System.out.print("Enter a number: ");
            x = Integer.parseInt(new Scanner(System.in).nextLine());
        } catch (NumberFormatException e) {
            x = 0;
        }
    }

    String y;
    {
        System.out.print("Enter a string: ");
        y = new Scanner(System.in).nextLine();
        for(int i = 0; i < 3; i++)
            y += y;
    }

    public InstanceInitializer() {
        System.out.println("The value of x is "+x);
        System.out.println("The value of y is "+y);
    }

    public static class ChildInstanceInitializer extends InstanceInitializer {
        {
            y = "a new value set by the child AFTER construction";
        }
    }

    public static void main(String[] args){
        new InstanceInitializer();
        new InstanceInitializer();
        System.out.println();
        System.out.println(new ChildInstanceInitializer().y);
        // This is essentially the same as:
        System.out.println(new InstanceInitializer(){
            {y = "a new value set by the child AFTER construction";}
        }.y);
    }
}

Этот вывод (что-то вроде):

Enter a number: 1
Enter a string: a
The value of x is 1
The value of y is aaaaaaaa
Enter a number: q
Enter a string: r
The value of x is 0
The value of y is rrrrrrrr

Enter a number: 3
Enter a string: b
The value of x is 3
The value of y is bbbbbbbb
a new value set by the child AFTER construction
Enter a number: s
Enter a string: Hello
The value of x is 0
The value of y is HelloHelloHelloHelloHelloHelloHelloHello 
a new value set by the child AFTER construction

Обратите внимание, что строка "новое значение" не установлена ​​до тех пор, пока уже не будет вызван конструктор родительского класса.