目录
<cinit>()V方法
一个类在加载的时候,编译器会按从上至下的顺序,收集所有 static 静态代码块和静态成员赋值的代码,合并为一个特殊的方法 <cinit>()V :并调用。
对应字节码
<init>()V
编译器会按从上至下的顺序,收集所有
{}
代码块和成员变量赋值的代码,形成新的构造方法,但原始构 造方法内的代码总是在最后
private String a = "s1";
{
b = 20;
}
private int b = 10;
{
a = "s2";
}
{
}
public Demo3_8_2(String a, int b) {
this.a = a;
this.b = b;
}
public static void main(String[] args) {
Demo3_8_2 d = new Demo3_8_2("s3", 30);
System.out.println(d.a);
System.out.println(d.b);
}
对应字节码
方法调用
对应字节码
- new 是创建【对象】,给对象分配堆内存,执行成功会将【对象引用】压入操作数栈
- dup 是复制操作数栈栈顶的内容,本例即为【对象引用】,为什么需要两份引用呢,一个是要配合 invokespecial 调用该对象的构造方法 "<init>":()V (会消耗掉栈顶一个引用),另一个要 配合 astore_1 赋值给局部变量
- 最终方法(fifinal),私有方法(private),构造方法都是由 invokespecial 指令来调用,属于静 态绑定 普通成员方法是由 invokevirtual 调用,属于动态绑定,即支持多态
- 成员方法与静态方法调用的另一个区别是,执行方法前是否需要【对象引用】 比较有意思的是 d.test4(); 是通过【对象引用】调用一个静态方法,可以看到在调用 invokestatic 之前执行了 pop 指令,把【对象引用】从操作数栈弹掉了,所以通过对象引用调用一个静态方法会产生两条无用指令。
- 还有一个执行 invokespecial 的情况是通过 super 调用父类方法