为什么选择java Instance初始化器?

Ahm*_*eed 29 java

Java中的"Instance Initializers"有什么意义?
我们不能只将那段代码放在构造函数的开头吗?

Boh*_*ian 38

我经常使用它们,通常用于在一个语句中创建和填充Map(而不是使用丑陋的静态块):

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

一个有趣且有用的装饰是在一个声明中创建一个不可修改的地图:

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

比使用静态块更简洁,并处理最终的奇异赋值等.

另一个提示:不要害怕创建简化实例块的方法:

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);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 对于使用实例初始值设定项进行收集的人群,请将[Guava Library](http://code.google.com/p/guava-libraries/)视为更优雅,更强大的替代方案.[`Maps`](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Maps.html)类提供了很好的Map实用程序,它们的`Immutable*`类是对于此处描述的用例特别好,请参阅[`ImmutableMap`](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html). (3认同)
  • 看起来像一个经典的代码示例,只有程序员自己才能阅读(在他写完之后一年,直到他忘记了他在想什么......);) (3认同)
  • @goldencalf它是一个匿名类,它是一个(on-the-fly)子类*,所以`put()`是一个实例方法,在`this`上隐式调用 - 就像你可以调用`toString()`从任何实例方法,而不必编码`this.toString()`.在这个例子中,我添加了一个重载版本的`put()`,它只接受一个参数,并且只在类定义中可见. (2认同)

Aas*_*set 24

您确实可以将代码放在每个构造函数的开头.但是,这正是实例初始化器的重点:它的代码应用于所有构造函数,如果你有许多构造函数和一些对所有构造函数都通用的代码,这可能很方便.

(如果您刚刚开始编程,您可能不知道可以为同一个类创建许多构造函数(只要它们采用不同的参数);这称为构造函数重载.如果您只有一个构造函数,然后实例初始化程序确实不是很有用(编辑:除非你在创意时尚中滥用它,如其他答案中所示).)


Nat*_*hes 7

您可以在声明匿名类时使用实例初始值设定项,例如,在执行Double Brace Initialization Idiom时.

List<String> mylist = new ArrayList<String>(){{add("a"); add("b"); add("c");}};
Run Code Online (Sandbox Code Playgroud)

在这里,您可以初始化对象,即使您无法向构造函数添加任何内容(因为该类是匿名的).

  • 但是,在这种特殊情况下,我建议使用`java.util.Arrays.<T> asList(T ... ts)`而不是:-) (2认同)

dim*_*414 5

由于这里的所有代码示例都使用匿名类,因此我将这个(稍微可怕的)类放在一起,该类演示了在"适当"类中使用实例初始化器.您可以使用它们执行复杂处理或在初始化时处理异常.请注意,这些块在构造函数运行之前运行,构造函数在子类中的初始化程序运行之前运行:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这输出(类似):

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
Run Code Online (Sandbox Code Playgroud)

请注意,直到已经调用父类的构造函数之后才会设置"新值"字符串.