类加载,在 java 基础文档的第一篇内容中就已经提到过,会经过以下流程:

  • java 源文件 经过 编译,生成 class 字节码文件
  • 进入到类加载器
  • 再经过字节码校验器
  • 解释器
  • 最终运行在操作系统平台

也就是说类加载动作发生在程序代码执行之前。但在代码当中有一个东西是跟类加载息息相关的,就是类里面 static 所修饰的内容。

其中,特别是静态代码块中的代码是在加载期就被执行的,所以我们需要知道 static 静态代码块在继承关系下所体现出来的特性。

创建父类对象时静态代码块的现象

当有父子两类存在,只创建父类实例时的现象:

  1. // Parent.java
  2. public class Parent {
  3. public String name;
  4. public int age;
  5. public String gender = "male";
  6. // 静态代码块
  7. static {
  8. System.out.println("父类的静态代码块被执行");
  9. }
  10. public Parent() {
  11. System.out.println("父类的无参构造被执行");
  12. }
  13. public Parent(String name, int age, String gender) {
  14. this.name = name;
  15. this.age = age;
  16. this.gender = gender;
  17. System.out.println("父类构造函数被调用");
  18. }
  19. }
  1. // Child.java
  2. public class Child extends Parent {
  3. static {
  4. System.out.println("子类的静态代码块被执行");
  5. }
  6. public Child() {
  7. System.out.println("子类的无参构造被执行");
  8. }
  9. public Child(String name, int age, String gender) {
  10. this.name = name;
  11. this.age = age;
  12. this.gender = gender;
  13. System.out.println("子类构造函数被调用");
  14. }
  15. }
  1. // TestMain.java
  2. Parent p = new Parent(); // 输出:父类父类的静态代码块被执行 父类的无参构造被执行

image-20220512100451156.png
由此可以看出,当程序中需要 使用 到哪个类,就会加载哪个类,也就会执行它的静态代码块。

创建子类对象时静态代码块的现象

同样的文档结构,创建子类时,静态代码块的现象:
image-20220512100314378.png
此时会发现,当 new 子类时,父类、子类都会被加载,或者说 new 子类时也会自动加载它的父类。子类代码中有一部分属性行为是共有于父类、继承于父类的,所以单加载子类是不够的,若不加载父类那么共有部分则会信息丢失。
所以加载的顺序:先父类再子类。

创建父子类对象时静态代码块的现象

那如果同时创建父类对象和子类对象呢?观察静态代码块的现象:
image-20220512100944036.png
当父类子类同时创建对象,类只需要加载一次,或者说 一个类只会被加载一次,那么创建子类时就不需要重复加载父类。
现在的 java 虚拟机在加载时采用 JIT(just in time) ——即时加载。它不会预先把要用的类进行加载,而是边执行边加载。