先从一段代码说起
众所周知,Java如果不手动写构造方法,它也有默认的构造方法
- 代码
public class InitTest {
String str= "Welcome";
private int anInt = 5;
public static Integer integer = 10;
//没有显示定义构造方法
public static void main(String[] args) {
}
}
其字节码
并不是如代码中看到的那样
如上图可见
- 首先,字节码生成了默认构造方法
<init>。 - 其次,给变量赋值并不像代码中写的那样依次赋值,而是在默认构造方法中赋值。
- 最后,细心如我,发现,被
static修饰的integer并没有出现。
如果手动在Java代码中声明构造方法会怎么样?
- 代码如下
public class InitTest {
String str= "Welcome";
private int anInt = 5;
public static Integer integer = 10;
public InitTest(){
//构造0
}
public InitTest(int a){//构造2
//构造1
}
public static void main(String[] args) {
}
}
- 字节码。毫无疑问会员两个构造方法
- 可以看见两个构造方法中的字节码一样
- 就像是把赋值代码搬运到了构造方法中,不管你给成员变量赋值是在代码的第一行还是最后一行,都会被搬运进构造方法中。
- 这就是指令重排序。
关于静态方法和静态成员变量的赋值
都是在 <clinit> 中
- 代码如下
public class InitTest {
String str= "Welcome";
private int anInt = 5;
public static Integer integer = 10;
public InitTest(){//构造1
}
public InitTest(int a){//构造2
}
static {
System.out.println("static block");
}
static {
int aa = 100;
}
public static void main(String[] args) {
}
}
- 字节码如下
- 可以看见
- 静态成员变量是在
<clinit>中完成的赋值。 - 不管代码中有几个静态代码块,最后都会被合并到
<clinit>中。
- 静态成员变量是在
小结
关于构造方法 <init>。
- 就是给成员变量赋值的,不管你赋值的代码是在构造方法外面还是里面,就算构造方法里面没有声明代码,给成员变量赋值的代码也会被移到构造方法中。
- 当然静态成员变量除外。
关于静态成员变量和静态代码块
- 静态成员变量的赋值操作会被移到
<clinit>中。 - 多个静态代码块会被合并到
<clinit>中。