• Java经典面试题:static加载机制你知道吗?


    static在Java中是一个很常见的关键字,同时它也是面试时的一个高频考点。那么在Java类中,static的加载机制到底是怎样的呢?接下来百泽老师就来带大家弄明白这个问题。

    一. 类加载机制

    JVM在首次使用某个类时,会通过 classpath 来查找该类的.class文件。然后将.class文件中对类的描述信息加载到内存中进行保存,如:包名、类名、父类、属性、方法、构造方法......一个类的加载过程大致如下:

    • 加载时机

    • 创建对象

    • 创建子类对象

    • 访问静态属性

    • 调用静态方法

    • 主动加载:Class.forName(“全限定名”)

    二. static 特点

    static关键字修饰的类或方法、成员等具有如下特点:

    • 静态方法允许直接访问静态成员

    • 静态方法不能直接访问非静态成员;

    • 静态方法中不允许使用this或是super关键字;

    • 静态方法可以继承,不能重写、没有多态。

    三. 经典面试题

    接着我们再来看看关于static的一个经典面试题,代码案例如下:

    1. public class Test {
    2.    
    3.     public static int k = 0;
    4.     public static Test t1 = new Test("t1");
    5.     public static Test t2 = new Test("t2");
    6.     public static int i = print("i");
    7.     public static int n = 99;
    8.     
    9.     private int a = 0;
    10.     
    11.     public int j = print("j");
    12.     
    13.     {
    14.         print("构造代码块");
    15.     }
    16.     
    17.     static{
    18.         print("静态构造代码块");
    19.     }
    20.     
    21.     public Test(String str){
    22.         System.out.println((++k)+":"+str+"  i="+i+"  n="+n);
    23.         ++i;
    24.         ++n;
    25.     }
    26.     
    27.     public static int print(String str){
    28.         System.out.println((++k)+":"+str+" i="+i+" n="+n);
    29.         ++n;
    30.         return ++i;
    31.     }
    32.     
    33.     public static void main(String[] args) {
    34.                 
    35.     }
    36. }

    这是一道关于static加载执行顺序的经典面试题,根据代码观察执行结果,接下来我们就来分析一下上述代码的执行结果是什么。

    1.在执行 main 方法,也就是程序主入口的时候,首先会加载所在的类,声明静态变量,初始化静态属性,执行静态代码块(按照顺序执行),所以首先加载的是:

     public static int k = 0;

    2.其次加载:

    public static Test t1 = new Test("t1");

    3.而加载到实例化 t1 对象时,类的加载会暂停,然后创建 Test 的实例对象。在创建 Test 对象时则会先加载属性再执行代码块,最后执行构造方法,所以先执行的会是实例属性。

    1. private int a = 0;
    2. public int j = print("j");
    3. public static int print(String str){
    4.     System.out.println((++k)+":"+str+" i="+i+" n="+n);
    5.     ++n;
    6.     return ++i;
    7. }

    4.因加载类的过程中,会对定义的静态字段在方法区中分别分配空间,并赋予初始化值,所以 i 和 n 的值都为0,因此第一个打印语句是:

    1:j i=0 n=0

    5.实例属性加载完毕后,则进行构造代码块的加载:

    1. {
    2.     print("构造代码块");
    3. }
    4. public static int print(String str){
    5.     System.out.println((++k)+":"+str+" i="+i+" n="+n);
    6.     ++n;
    7.     return ++i;
    8. }

    6.因为第一次调用时已经对 k 、i 、n 的值进行了自加,因此第二个打印语句是:

    2:构造代码块 i=1 n=1

    7.实例化对象的最后一步,则是执行构造方法:

    1. public static Test t1 = new Test("t1");
    2. public Test(String str){
    3.     System.out.println((++k)+":"+str+"  i="+i+"  n="+n);
    4.     ++i;
    5.     ++n;
    6. }

    8.因此第三个打印语句是:

    3:t1  i=2  n=2

    9.t1 对象创建完毕后,类加载则继续执行,因此下一步则是:

    public static Test t2 = new Test("t2");

    10.按照前面实例化 t1 的执行机制,因此接下来的打印的几句则是:

    1. 4:j i=3 n=3
    2. 5:构造代码块 i=4 n=4
    3. 6:t2  i=5  n=5

    11.实例化完 t2 对象后,继续进行类加载,因此下一步加载静态属性 i 的赋值:

    1. public static int i = print("i");
    2. public static int print(String str){
    3.     System.out.println((++k)+":"+str+" i="+i+" n="+n);
    4.     ++n;
    5.     return ++i;
    6. }

    12.因此下一步打印结果为:

    7:i i=6 n=6

    13.加载完最后一个静态属性 n= 99 后,则加载静态构造代码块:

    1. public static int n = 99;
    2. static{
    3.      print("静态构造代码块");
    4. }
    5. public static int print(String str){
    6.     System.out.println((++k)+":"+str+" i="+i+" n="+n);
    7.     ++n;
    8.     return ++i;
    9. }

    14.因此最后会打印:

    8:静态构造代码块 i=7 n=99

    15.所以整体的执行结果会是:

    1. 1:j i=0 n=0
    2. 2:构造代码块 i=1 n=1
    3. 3:t1  i=2  n=2
    4. 4:j i=3 n=3
    5. 5:构造代码块 i=4 n=4
    6. 6:t2  i=5  n=5
    7. 7:i i=6 n=6
    8. 8:静态构造代码块 i=7 n=99

    四. 小结

    现在你知道一个Java类的加载执行机制了吗?可以说,掌握 static 在程序中的加载执行顺序,可以使我们更好地理解代码,明白程序的执行流程。

  • 相关阅读:
    Django(根据Models中模型类反向生成数据库表)—— python篇
    AppLink结合金蝶云星空作订单信息同步流程
    Java 程序设计报告[对接java的迭代器接口]
    使用 curator 连接 zookeeper 集群 Invalid config event received
    thinkphp队列的使用?
    【日常】一名开发人员总结的好习惯,欢迎补充
    Target DVS 的 EDI SaaS解决方案—— LIP 操作详解
    C语言之 结构体,枚举,联合
    【雷达原理】雷达信号级建模与仿真
    【C++】类和对象(中)
  • 原文地址:https://blog.csdn.net/finally_vince/article/details/127731507