首先这个问题很有意思,不过题主没具体指明放在何处的代码块。
这里至少有三种情况,第一种就是在普通的方法里面,第二种是实例初始化代码块,第三种是静态初始化代码块。
第一种情况
使用javap反汇编了一下有代码块的代码和无代码块的代码。结果比较后发现它们居然是一样的。
public class HelloWorld {
public void main(String[] args) {
int n = 1;
System.out.println(n);
// {int m = 2;
System.out.println(m);
// }}
}
然后执行一下javac HelloWorld.java && javap -c HelloWorld看汇编代码
public class HelloWorld {
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_2
2: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
5: iload_2
6: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
9: iconst_2
10: istore_3
11: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_3
15: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
18: return
}
所以我得出结论,普通代码块仅是词法语法层面的,对运行时没有影响,也就是说不存在所谓的「进入代码块入栈保存程序状态,出代码块再通过出栈来恢复程序状态」这种只有函数代码块才会出现的步骤。
第二种情况
实例初始化代码块里面的代码会被自动添加到「所有的构造器」的开头,代码块本身无额外压栈弹栈操作。而且要注意的是,这里说的是「所有的构造器」,有几个构造器,汇编代码中就会出现多少的冗余片段。如果有很多构造器,那就会有相当的浪费。
public class UserDB {
private Map rows = new HashMap<>();
{
rows.put("Linus", "linux");
rows.put("Neumann", "math");
rows.put("Turing", "gay");
}
public boolean checkAccess(String name, String passwd) {
return rows.containsKey(name) && rows.get(name).equals(passwd);
}
}
第三种情况
静态代码块是一个非常特殊的代码块,编译器会将同一个类中所有的静态代码块合并成一个函数static{},它们共享一次压栈弹栈操作。
public class UserDB {
private static Map rows = new HashMap<>();
static {
rows.put("Linus", "linux");
rows.put("Neumann", "math");
rows.put("Turing", "gay");
}
public boolean checkAccess(String name, String passwd) {
return rows.containsKey(name) && rows.get(name).equals(passwd);
}
}