阅读 53

JVM 字节码之构造方法和静态代码块

先从一段代码说起

众所周知,Java如果不手动写构造方法,它也有默认的构造方法

  • 代码
public class InitTest {
    String str= "Welcome";
    private int anInt = 5;
    public static Integer integer = 10;
    //没有显示定义构造方法
    public static void main(String[] args) {

    }
}
复制代码

其字节码

并不是如代码中看到的那样

image.png

如上图可见

  • 首先,字节码生成了默认构造方法 <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) {
        
    }
}
复制代码
  • 字节码。毫无疑问会员两个构造方法

image.png

image.png

image.png

  • 可以看见两个构造方法中的字节码一样
    • 就像是把赋值代码搬运到了构造方法中不管你给成员变量赋值是在代码的第一行还是最后一行都会被搬运进构造方法中
    • 这就是指令重排序。

关于静态方法和静态成员变量的赋值

都是在 <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) {

    }
}
复制代码
  • 字节码如下

image.png

  • 可以看见
    • 静态成员变量是在 <clinit> 中完成的赋值。
    • 不管代码中有几个静态代码块,最后都会被合并到 <clinit> 中。

小结

关于构造方法 <init>

  • 就是给成员变量赋值的,不管你赋值的代码是在构造方法外面还是里面,就算构造方法里面没有声明代码,给成员变量赋值的代码也会被移到构造方法中。
  • 当然静态成员变量除外。

关于静态成员变量和静态代码块

  • 静态成员变量的赋值操作会被移到 <clinit> 中。
  • 多个静态代码块会被合并到 <clinit> 中。
文章分类
后端
文章标签