Java中的双括号初始化是什么?

Java中的双括号初始化是什么?,java,initialization,double-brace-initialize,Java,Initialization,Double Brace Initialize,Java中的双括号初始化语法({…})是什么?它是初始化集合的快捷方式 双大括号初始化创建从指定类(外部大括号)派生的匿名类,并在该类(内部大括号)内提供初始化器块。e、 g newarraylist(){{ 增加(1); 增加(2); }}; 请注意,使用此双括号初始化的效果是创建匿名内部类。创建的类有一个指向周围外部类的隐式指针。虽然这通常不是问题,但在某些情况下,例如序列化或垃圾收集时,它可能会导致悲伤,值得注意。这似乎与flash和vbscript中非常流行的with关键字相同。这是一

Java中的双括号初始化语法(
{…}
)是什么?

它是初始化集合的快捷方式

双大括号初始化创建从指定类(外部大括号)派生的匿名类,并在该类(内部大括号)内提供初始化器块。e、 g

newarraylist(){{
增加(1);
增加(2);
}};

请注意,使用此双括号初始化的效果是创建匿名内部类。创建的类有一个指向周围外部类的隐式
指针。虽然这通常不是问题,但在某些情况下,例如序列化或垃圾收集时,它可能会导致悲伤,值得注意。

这似乎与flash和vbscript中非常流行的with关键字相同。这是一种改变
这个
的方法,仅此而已

有关双大括号初始化的有趣应用,请参见此处

摘录

private static class IndustrialRaverMonkey
  extends Creature.Base {{
    life = 46;
    strength = 35;
    charisma = 91;
    weapon = 2;
  }}

private static class DwarvenAngel
  extends Creature.Base {{
    life = 540;
    strength = 6;
    charisma = 144;
    weapon = 50;
  }}

现在,做好准备,迎接葛罗图·奥斯盖斯气味之战,还有……大块培根

你的意思是这样的

List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}};
List blah=newarraylist(){{add(“asdfa”);add(“bbb”);};

这是在创建时初始化数组列表(hack)

您可以将一些Java语句作为循环来初始化集合:

List<Character> characters = new ArrayList<Character>() {
    {
        for (char c = 'A'; c <= 'E'; c++) add(c);
    }
};
List characters=new ArrayList(){
{

for(char c='A';c每当有人使用双括号初始化时,小猫就会被杀死。

除了语法非常不寻常而且不是真正地道的(当然,品味是有争议的),您在应用程序中不必要地产生了两个重要问题


1.你创建的匿名类太多了 每次使用双大括号初始化时,都会生成一个新类。例如,此示例:

Map source = new HashMap(){{
    put("firstName", "John");
    put("lastName", "Smith");
    put("organizations", new HashMap(){{
        put("0", new HashMap(){{
            put("id", "1234");
        }});
        put("abc", new HashMap(){{
            put("id", "5678");
        }});
    }});
}};
…将生成以下类:

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
这对你的类加载器来说是相当大的开销——毫无意义!当然,如果你只做一次,初始化时间不会太长。但是如果你在整个企业应用程序中做了20000次,那么所有堆内存仅仅是为了一点“语法糖”

2.您可能正在创建内存泄漏!

如果您采用上述代码并从方法返回该映射,则该方法的调用方可能会毫不犹豫地持有无法被垃圾收集的非常重的资源。

public class ReallyHeavyObject {

    // Just to illustrate...
    private int[] tonsOfValues;
    private Resource[] tonsOfResources;

    // This method almost does nothing
    public Map quickHarmlessMethod() {
        Map source = new HashMap(){{
            put("firstName", "John");
            put("lastName", "Smith");
            put("organizations", new HashMap(){{
                put("0", new HashMap(){{
                    put("id", "1234");
                }});
                put("abc", new HashMap(){{
                    put("id", "5678");
                }});
            }});
        }};

        return source;
    }
}
返回的
Map
现在将包含对
ReallyHeavyObject
的封闭实例的引用。您可能不想冒险:

来自

3.您可以假装Java有映射文本 为了回答您的实际问题,人们一直在使用这种语法来假装Java有类似于map文本的东西,类似于现有的数组文本:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};
有些人可能会觉得这在句法上很刺激。

  • 第一个大括号创建一个新的匿名内部类
  • 第二组大括号创建了一个实例初始值设定项,如类中的静态块
例如:

   public class TestHashMap {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<String,String>(){
        {
            put("1", "ONE");
        }{
            put("2", "TWO");
        }{
            put("3", "THREE");
        }
        };
        Set<String> keySet = map.keySet();
        for (String string : keySet) {
            System.out.println(string+" ->"+map.get(string));
        }
    }
    
}
公共类TestHashMap{
公共静态void main(字符串[]args){
HashMap=newHashMap(){
{
付诸表决(“1”、“1”);
}{
付诸表决(“2”、“2”);
}{
付诸表决(“3”、“3”);
}
};
Set keySet=map.keySet();
for(字符串:键集){
System.out.println(字符串+“->”+map.get(字符串));
}
}
}
它的工作原理

第一个大括号创建一个新的匿名内部类。这些内部类能够访问其父类的行为。因此,在本例中,我们实际上是在创建HashSet类的一个子类,因此该内部类能够使用put()方法

第二组大括号只不过是实例初始值设定项。如果您记住了核心java概念,那么由于类似大括号的结构,您可以轻松地将实例初始值设定项块与静态初始值设定项相关联。唯一的区别是静态初始值设定项添加了static关键字,并且只运行一次;无论运行多少次创建的对象


避免双支架初始化的所有负面影响,例如:

  • 打破了“等于”的兼容性
  • 使用直接分配时,不执行检查
  • 可能的内存泄漏
  • 做下一件事:

  • 创建单独的“Builder”类,特别是用于双大括号初始化的类
  • 使用默认值声明字段
  • 将对象创建方法放在该类中
  • 例如:

    public class MyClass {
        public static class Builder {
            public int    first  = -1        ;
            public double second = Double.NaN;
            public String third  = null      ;
    
            public MyClass create() {
                return new MyClass(first, second, third);
            }
        }
    
        protected final int    first ;
        protected final double second;
        protected final String third ;
    
        protected MyClass(
            int    first ,
            double second,
            String third
        ) {
            this.first = first ;
            this.second= second;
            this.third = third ;
        }
    
        public int    first () { return first ; }
        public double second() { return second; }
        public String third () { return third ; }
    }
    
    用法:

    MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();
    
    优势:

       public class TestHashMap {
        public static void main(String[] args) {
            HashMap<String,String> map = new HashMap<String,String>(){
            {
                put("1", "ONE");
            }{
                put("2", "TWO");
            }{
                put("3", "THREE");
            }
            };
            Set<String> keySet = map.keySet();
            for (String string : keySet) {
                System.out.println(string+" ->"+map.get(string));
            }
        }
        
    }
    
  • 简单地使用
  • 不要破坏“相等”兼容性
  • 您可以在创建方法中执行检查
  • 没有内存泄漏
  • 缺点:

       public class TestHashMap {
        public static void main(String[] args) {
            HashMap<String,String> map = new HashMap<String,String>(){
            {
                put("1", "ONE");
            }{
                put("2", "TWO");
            }{
                put("3", "THREE");
            }
            };
            Set<String> keySet = map.keySet();
            for (String string : keySet) {
                System.out.println(string+" ->"+map.get(string));
            }
        }
        
    }
    
    • 没有
    因此,我们有了最简单的JavaBuilder模式


    查看github上的所有示例:

    1-没有双括号:
    我想指出的是,没有双大括号初始化。只有普通的传统的单大括号初始化块。第二个大括号块与初始化无关。答案说这两个大括号初始化了一些东西,但不是这样

    2-不仅仅是匿名类,而是所有类:
    几乎所有的答案都说这是在创建匿名内部类时使用的。我认为阅读这些答案的人会得到这样的印象,即这只在创建匿名内部类时使用。但它在所有类中都使用。阅读这些答案看起来是专为匿名类和我认为这是误导

    3-目的只是将括号放在彼此后面,而不是新概念:{ // whatever code is needed for initialization goes here }