虚拟机类加载机制【概述及类加载时机】

2021-07-28  本文已影响0人  云芈山人

概述

Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略虽令类加载时稍微增加一些性能开销,但是会为程序提供更高的灵活性,Java里天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。如编写一个面向接口的应用程序,可以等到运行时再指定其实际的实现类。从最基础的Applet、JSP到相对复杂的OSGi技术,都使用了Java语言运行期类加载的特性。

类加载的时机

以下为被动引用的例子

1. 通过子类引用父类的静态字段,不会导致子类初始化。

package com.test;

public class SuperClass {

    static {
        System.out.println("SuperClass init!");
    }
    
    public static int value = 123;
    
}

package com.test;

public class SubClass extends SuperClass {

    static {
        System.out.println("SubClass init!");
    }
}
package com.test;

public class Test {

    public static void main(String[] args) {
        //通过子类引用父类的静态字段,不会导致子类初始化
        System.out.println(SubClass.value);
    }
    
}
SuperClass init!
123

2. 通过数组定义来引用类,不会触发此类的初始化。

package com.test;

public class SuperClass {

    static {
        System.out.println("SuperClass init!");
    }
    
    public static int value = 123;
    
}

package com.test;

public class SubClass extends SuperClass {

    static {
        System.out.println("SubClass init!");
    }
}
package com.test;

public class Test {

    public static void main(String[] args) {
        //通过数组定义来引用类,不会触发此类的初始化。
        SuperClass[] sca = new SuperClass[10];
    }
    
}

3. 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

package com.test;

public class ConstClass {

    static {
        System.out.println("ConstClass init!");
    }
    
    public static final String HELLOWORLD = "hello word";
    
}
package com.test;

public class Test {

    public static void main(String[] args) {
        //常量在编译阶段会存入调用类的常量池中,
        //本质上并没有直接引用到定义常量的类,
        //因此不会触发定义常量的类的初始化
        System.out.println(ConstClass.HELLOWORLD);
    }
    
}
hello word

接口与类加载的区别

上一篇 下一篇

猜你喜欢

热点阅读