2011-11-13 39 views
3
public class A{ 
} 

A a = new A(){{ 
    final int x = 1; // IT HAS TO BE FINAL HERE. WHY? 
}}; 

A aa = new A(){ 
    int x = 1; // THIS NEED NOT BE FINAL. WHY? 
    final int y = 1; // STILL FINAL IS ALLOWED HERE. WHY? 
    public int getX(){ 
     return x; 
    } 
}; 

有人可以回答在代码段中提到的问题吗?Java中{}和{{}}初始化的区别

由于

回答

3
A a = new A(){{ 
    final int x = 1; // IT HAS TO BE FINAL HERE. WHY? 

It needn't.

两者之间的区别是,在第一种情况下,你写的用于初始化每个对象在双括号中的代码。那x是它的局部变量(与A类的对象没有任何关系)。

在第二种情况下,您正在定义类体。 x将是其成员变量。如果它是static,它的类变量。如果final一(基本上)不变。

+0

有没有解释Java语言的基本细节的Java书? – user855

+0

@ajay是的,它被称为[Java语言规范](http://java.sun.com/docs/books/jls/)。 –

1

第一个实例A a = new A(){{...具有声明中的初始化块。编写它的另一种方式是这样的:

A a = new A() 
{ 
    { 
     final int x = 1; // This is inside an initialisation block 
    }   
}; 

更改格式使其更加明显。

+0

为什么静态初始化块不允许在其中放置static final int x = 1? – user855

+1

第一个实例没有静态初始化块,它有一个实例初始化块。你可以把东西放在引用实例的块中(双引号初始化技巧是如何工作的)。 –

+0

内部{}是一个初始化块,但不是_static_。如果它是静态的,它会在它之前有关键字'static' - 但是你不能在匿名内部类中使用静态初始化器。 –

2

我想知道,为什么要使用第一版的代码(带有{{}}的代码)。在其中声明的变量x根本就没有用处,它只在本地定义它的块范围,并且在匿名类中,所以您将无法在代码中的任何位置引用它。

反正x声明的第一个版本不必须final,它编译一样细,有或没有final

+1

你会使用双大括号版本,因为它是一个成语:http://c2.com/cgi/wiki?DoubleBraceInitialization我个人认为这不是一个很好的;它掩盖了惊人的开销。 –

4

外集{}声明一个子类匿名

内集声明子类中的初始化块。

通过下面的例子,它变得更容易理解这是怎么回事:

List<String> strings = new ArrayList<String>() {{ 
    add("string"); 
    add("another string"); 
}}; 

你基本上说:我想列出的一个子类,它在初始化时调用方法add

它类似于:

List<String> strings = new ArrayList<String>(); 
strings.add("string"); 
strings.add("another string"); 
+2

内部{}是一个初始化块,但不是_static_。如果它是静态的,它会在它之前有关键字'static' - 但是你不能在匿名内部类中使用静态初始化器。 –

+0

的确,我写得太快了:)编辑出来,谢谢。 – Guillaume

1

在你的第一个例子中的括号内创造一种叫做实例初始化。在构建对象时,初始化变量和调用实例方法是一种难以理解的方式。因此,第一个示例创建了A的匿名子类,并在初始化程序的范围内创建了一个局部变量。它不一定是最终的。

在第二个示例中,您正在创建A的匿名子类,但未创建实例初始值设定项,您创建的变量是匿名子类的实例变量。

相关问题