Java中的"new Foo(){}"和"new Foo()"有什么区别?

14
例如:
Object o1 = new ArrayList<String>();
Object o2 = new ArrayList<String>(){};
Object o3 = new ArrayList<String>(){{}};

有什么区别?

我无法在谷歌上找到Java的第二/第三语法,有参考资料吗?


2
可能是重复的内容:面试:我们能否实例化抽象类? - Rohit Jain
第三个是声明匿名类的实例初始化块。 - Sotirios Delimanolis
1
关于第三个问题,http://www.c2.com/cgi/wiki?DoubleBraceInitialization - Matt Ball
2
new ArrayList<String>(){{{{{{}}}}}} 仍然是合法的 :p - nneonneo
很有趣看到第三个,我们该如何称呼第三个符号? - SimonT
1
@SimonT 双括号初始化,但尽量避免使用它。 - arshajii
7个回答

25

第一个创建了一个ArrayList。

第二个创建了一个匿名的ArrayList子类,其具有特定的String泛型类型。

第三个与第二个相同,但它具有一个空的初始化块。

注意:在可能的情况下,应尽量编写最简单和最清晰的代码,特别是如果您正在考虑性能。


4
我认为你应该添加这样一句话:“除非有详细的注释解释需要使用匿名类来规避反射的奇怪特殊需求,否则第二种和第三种情况都是很愚蠢、令人困惑和错误的。” - user949300
1
我会补充一下,JMock 用第三种风格来创建模拟对象并编码期望。 - Sled

13
Object o1 = new ArrayList<String>();

创建一个ArrayList。

Object o2 = new ArrayList<String>(){};

在这里,你正在创建一个匿名类,它继承自 ArrayList<String> 并且没有覆盖任何内容。所以,与覆盖行为的子类不同,你正在子类化一个 ArrayList,如果没有充分的理由,请不要这样做

Object o3 = new ArrayList<String>(){{}};

您正在创建与2相同的内容,但带有一个空的初始化器块。


谢谢!明白了。也许第二个对于避免“类型擦除”有用? - marstone
2
@marstone。不,那不是正确的用法。类型擦除是无法避免的。 - Rohit Jain
@RohitJain 如果不是这样,谷歌的gson如何通过使用“new TypeToken <ArrayList <String>>(){} .getType()”来保留通用参数类型?如果这超出了话题,请原谅。 - marstone
1
@marstone,他们使用反射的黑魔法,这与匿名子类无关,你可以在这里找到一些细节(https://code.google.com/p/guava-libraries/wiki/ReflectionExplained)。 - Katona
@Katona:这绝对与匿名子类有关;我不确定您如何否认这一点。子类化允许类型参数在擦除后仍然可用于运行时。 (当然,只能使用反射的黑魔法来使用它,但是如果没有子类化,即使那么多也是不可能的。) - ruakh
@ruakh,好的,让我纠正一下,它与子类化有关,但不必是匿名的,当然也不会防止类型擦除。 - Katona

2
Object o1 = new ArrayList<String>();

创建一个新的ArrayList对象并将其分配给o1
Object o2 = new ArrayList<String>(){};

创建一个继承自ArrayList的匿名类的新实例,并将其分配给o2
Object o3 = new ArrayList<String>(){{}};

创建一个继承自ArrayList的匿名类实例(不同于o2),该类具有无操作实例初始化程序。

在功能上,分配给o2o3的匿名类是等效的,但从技术上讲,它们将是不同的类。


0
// Instantiate an object of type `ArrayList<String>`
Object o1 = new ArrayList<String>();

// Instantiate an anonymous subclass of `ArrayList<String>`
Object o2 = new ArrayList<String>(){};

// Instantiate an anonymous subclass of `ArrayList<String>` with an empty initializer block
Object o3 = new ArrayList<String>(){{}};

0

您正在匿名实例化一个类。在后一种情况下,您可以覆盖方法而无需在自己的文件中定义新类。


0

o3 仍然是 ArrayList 的一个匿名子类的实例,该子类具有一个空的实例初始化块(内部的 {})。


0

Object o2 = new ArrayList<String>(){};
这是一个继承了ArrayList类并且没有重写任何方法的匿名内部类。
Object o2 = new ArrayList<String>(){{}};
这也是一个继承了ArrayList类并且没有重写任何方法,但是有一个空的实例块的匿名内部类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接