二重括弧の初期化の理解

4161 ワード

偶然初期化方式を見て、とても珍しいと感じました.
    //          A、B、C
    ArrayList<String> list = new ArrayList<String>() {{
        add("A");
        add("B");
        add("C");
    }};

HashMapの初期化などの他の集合もあります.
    Map map = new HashMap() {{ 
      put("Name", "Unmi"); 
      put("QQ", "1125535"); 
    }};

この方式は先にnewがオブジェクトを出すよりも、もう1本のaddで、より簡潔で優雅に見えます.最初は何の原理も考えられなかったが、後で調べてみると、この方法は二重カッコ初期化(double brace initialization)や匿名内部クラス初期化法と呼ばれ、実際には巧みな方法であることが分かった.
理解:
ここでArrayListの例として説明すると、まず第1層のカッコは、ArrayListに継承された匿名の内部クラス(Anonymous Inner Class)を定義する.
//        ArrayList  ,     
new ArrayList<String>(){
  //             
};

第2層の括弧は、実際にはこの匿名の内部クラスインスタンス初期化ブロック(Instance Initializer Block)(または非静的初期化ブロックと呼ばれる)である.
new ArrayList<String>(){
  {
    //         ,                      
  }
};

このArrayListのサブクラスのインスタンスをnewによって取得し、ArrayListの参照にアップコンバートします.
 ArrayList<String> list = new ArrayList<String>() {{}};
  • 実際にはArrayListのサブクラスの参照を得ていますが、このサブクラスはArrayListに比べて機能的な変更はありません.
  • は、参照を取得してから値を付与するのではなく、自身がデータを装着しているサブクラスであると考えられる.

  • 次にクラスをカスタマイズし、この方法で初期化します.
    class Person{
      protected String name;
      protected int age;
    
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
      public int getAge() {
        return age;
      }
      public void setAge(int age) {
        this.age = age;
      }
    }
    ...
    public static void main(String[] args) {
      Person p = new Person(){
        {
          name = "xiaoming";  //    setName()
          age = 3;          //  setAge()
        }
      };
      System.out.println(p.getName() + p.getAge());
    }

    注意:
  • この方法は、コードをある程度簡潔にするが、同時に可読性を低下させる可能性がある.メモリの漏洩も発生し、シーケンス化時に問題が発生する可能性があります(テストされていません).

  • コメントエリアの友人のコメントに感謝し、この問題をもっと深く理解させていただきました.^^;