在java中使用非静态块有什么用?

Ash*_*wyn 7 java

可能重复:
实例初始值设定项与构造函数有何不同?

当所有必需的工作都可以在构造函数内完成时,为什么我们仍然需要Java中的非静态块?

编辑:在构造函数之前每次运行非静态块的普通类怎么办?

Pet*_*rey 12

除了@ Bohemian的回答.

如果您有多个构造函数,则一个intialiser块可以避免重复.

public class A {
     final Map<String, String> map = new HashMap<String, String>(); {
        // put things in map.
     }
     final int number; {
        int number;
        try {
            number = throwsAnException();
        } catch (Exception e) {
            number = 5;
        }
        this.number = number;
     }

     public A() { /* constructor 1 */ }
     public A(int i) { /* constructor 2 */ }
}
Run Code Online (Sandbox Code Playgroud)

在构造函数之前每次运行非静态块的普通类怎么办?

从技术上讲,订单是

  • 总是首先调用超级构造函数
  • 所有初始化程序块按照外观顺序排列.
  • 构造函数代码

实际上,所有这些代码都在每个构造函数的字节代码中,因此在运行时构造函数之前或之后没有任何内容.


在对初始化顺序有任何混淆之前

public class Main extends SuperClass {
    {
        System.out.println("Initialiser block before constructor");
    }

    Main() {
        System.out.println("Main constructor");
    }

    {
        System.out.println("Initialiser block after constructor");

    }

    public static void main(String... args) {
        new Main() {{
            System.out.println("Anonymous initalizer block");
        }};
    }
}

class SuperClass {
    SuperClass() {
        System.out.println("SuperClass constructor");
    }
}
Run Code Online (Sandbox Code Playgroud)

版画

SuperClass constructor
Initialiser block before constructor
Initialiser block after constructor
Main constructor
Anonymous initalizer block
Run Code Online (Sandbox Code Playgroud)

  • @PeterLawrey匿名类的实例块在构造函数之后按照外观顺序执行*.也许在你的答案中区分出类中实例块的执行顺序.(ps祝贺100K,并为你的java连接器角色回答制作时事通讯!). (2认同)

Boh*_*ian 7

您可以将它与匿名类一起使用:

new MyClass() {
    {
         // do something extra on construction (after the constructor executes)
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现这对于初始化"查找"地图(即固定内容)特别有用:

Map<String, String> map = new HashMap<String, String>() {
    {
        put("foo", "bar");
        put("one", "two");
        // etc
    }
};
Run Code Online (Sandbox Code Playgroud)

仅供参考,这有时(很差)称为"双支撑初始化",实际上它只是采用初始化块.

虽然这样的匿名类在技术上是一个子类,但在使用这种技术与创建不可修改的映射时更传统的技术进行比较时,会显示出它的美妙之处:

比较这个直接的单行,将数据和赋值放在一起:

private static final Map<String, String> map = Collections.unmodifiableMap(
    new HashMap<String, String>() {{
        put("foo", "bar");
        put("one", "two");
        // etc
    }});
Run Code Online (Sandbox Code Playgroud)

有了这个混乱,由于final只允许一个赋值,它必须创建一个单独的对象:

private static final Map<String, String> map;

static {
    Map<String, String> tempMap = new HashMap<String, String>();
    tempMap.put("foo", "bar");
    tempMap.put("one", "two");
    // etc
    map = Collections.unmodifiableMap(tempMap);
}
Run Code Online (Sandbox Code Playgroud)

另请注意,对于混乱版本,这两个语句不必相邻,因此不可修改的映射的内容可能变得不那么明显.

  • 请注意,像这样初始化容器(称为"双括号初始化")(http://c2.com/cgi/wiki?DoubleBraceInitialization))会相当不恰当地创建子类 - 类似于子类化`Thread`被认为是不合适的你只想实现`Runnable`.滥用继承时要小心; 一个例子提到它如何打破`equals`的常见实现.您应该考虑使用[集合工厂方法](http://c2.com/cgi/wiki?VarargsCollectionFactoryMethod). (2认同)