在Java后端笔试中发现了从来没有遇到过的双括号语法,由此引发了对"{}"的归纳。

1. 作用域

“作用域”很常用,所以不用再讲了。。。吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class A extends B {
{ // 局部作用域
int a = 233;
}
private static int a;
static {
System.out.println("The initial value of a is " + a);
}
public static void fun(){
System.out.println("The is a function from A.");
}
public A() {
System.out.println("This is A, over.");
}

public static void main(String[] args) {
A a1 = new A();
B b1 = new A();
}
}
class B {
static {
System.out.println("Hello, I am B");
}

B() {
System.out.println("This is B, over.");
}
}

如果你能正确写出上述代码执行后的结果,那么确实不用看了。反之,你没有掌握。至于结果是什么,自己跑一跑便知。在这串代码中,在A类中有个局部作用域,在A,B中各自含有一个static静态区域。

其中,局部作用域中的代码是不会影响局部作用域外的private static int a的,而在类加载后,会将a初始化成0。

static静态区,类会在加载时编译,因此在实例化之前,就会输出。

2. 初始化数组

没什么的好讲的。

1
2
String[]   s = {"1","2","3"};
String[][] s = {{"1","2"},{"3","4"}};

3. 匿名类

1
2
3
4
new Thread(){
public void run(){
}
}.start();

4. 双括号

通常情况下,初始化Java集合并向其中添加几个元素的步骤如下:

1
2
3
4
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);

我们也可以在静态区域中向作为静态变量的集合中添加元素:

1
2
3
4
5
6
private static final Set<Integer> set = new HashSet<>();
static {
set.add(1);
set.add(2);
set.add(3);
}

此方法从语法上来看,这样的初始化方法虽然格式清晰明了,但语法上略显冗余。况且只能向“静态变量集合”中添加的约束,而“静态变量集合”只能作为一个类的内部私有属性,如果在”main”方法中便不能用了。

那么,双括号就出现了,也叫反模式。你可以在”main”中使用:

1
2
3
4
5
Set<Integer> set = new HashSet<Integer>() {{
add(1);
add(2);
add(3);
}};

也可以在类中,给类集合属性初始化:

1
2
3
4
5
6
7
8
public class Main {
private static final Set<String> stringSet = new HashSet<>(){{
add("I");
add("am");
add("stringSet");
}};
// ...others
}

这是比较特殊的用法。一般在做题的时候会遇到,考你的知识点,笔试时见到了不会自闭就够了。但是不建议使用,它可能会出现“内存溢出”的bug。

1
2
3
4
5
6
7
8
9
10
11
12
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");
}});
}});
}};

你可以试一试运行上述代码,表面上简洁的初始化代码,但是,编译器在为每个”双括号“实例化类型都创建了一个类,我们可以查看目录下的.class文件:
TwoBraces.png

其中带有$符号的文件,如Main$2$1.class是什么意思呢? 是Main下有个匿名类,它管这个匿名类叫”2“,而”2“的下面还有一个匿名类,它管这个匿名类叫”1“。

如此的话,你运行一次没毛病,但是但是如果类似这样的代码存在于一个大型的应用中,这将增加 ClassLoader 一些不必要的负担。所以我们尽量不要为了省事儿,去写双括号的形式。

参考链接

http://www.importnew.com/15087.html

Comments

⬆︎TOP