Java 类加载机制

最近开始投简历,有了第一次的笔试经历后。
发现要记的东西其实很多,不记下来总是容易忘记。
任何时候都不会太晚,现在就开始写博客了。
关于Java类的加载、
Java提供两种加载机制,一是预先装载,二是按需加载。按需加载的好处是程序启动时不需要把所有类都装载JVM中,大部分类延迟到需要用才加载,又称动态装载机制。
1.基础类加载。(采用预先装载)首先载入JDK目录下二等jvm.dll,然后启动虚拟机,并做一些初始化操作,如设置系统参数。最后创建BootstrapLoader对象(称为启动类装载器),负责一次性加载JVM基础类。

2.main()函数加载。刚说到BootstrapLoader,它有一项重要工作就是装在定义在sun.misc下的Launcher类。Launcher包含 ExtClassLoader 和AppClassLoader. 其中,ExtClassLoader 父加载器设置为null,表示其父加载器为BootStrapLoader,APPClassLoader的父加载器设置为ExtClassLoader,拥有main()函数的入口类。所以,main()函数由AppClassLoader在程序启动时加载

public class Bootstrap {
    static {
        System.out.println("Bootstrap prepare!");
    }

    public static void main(String[] args){
        ClassLoader loader = Bootstrap.class.getClassLoader();
        System.out.println(loader);
        System.out.println(loader.getParent());
        System.out.println(loader.getParent().getParent());
    }
}

运行结果:
在这里插入图片描述
说明:Bootstrap类在程序启动时就加载了。(Java类装载时会执行动态代码)
接着输出sun.misc.Launcher$AppClassLoader@18b4aac2是Bootstrap类的加载 器。然后输出sun.misc.Launcher$ExtClassLoader@1540e19d,是AppClasSLoader的父类。最后null表示ExtClassLoader父加载器为空,表示由BootstrapLoader直接装载。(内部类用$表示,说明AppClassLoader和ExtClassLoader都为内部类)

3.介绍按需加载。Java如何动态装载?什么条件触发JVM去装载?
1)当一个类的静态成员被第一次引用时,JVM就会去装载它。静态成员包括:(1)静态方法(2)静态属性(3)构造方法(是静态成员特例

public class Person {
    public static final int ID = 1;
    static{
        System.out.println("Person prepare!");
    }
}

public class Bootstrap {
    public static void main(String[] args){
        System.out.println("Use static field!");
        System.out.println(Person.ID);
        System.out.println("new a instance");
        new Person();
    }
}

在这里插入图片描述
结论:真正的初始化工作发生在使用new关键字构造对象时,而不是访问静态常量属性时。(由此也可以证明 构造方法是静态方法。)
2)按需装载流程
当需要使用一个类时,JVM首先检查这个类的Class对象是否已经加载。如果已加载,便可执行想执行的代码。如果未加载,则查找该类对应的.class文件,然后载入,并生成装载该类的Class对象。
装载并使用一个类,JVM需要完成以下三项工作:
(1)加载。查找并导入类的二进制字节码,根据字节码创建一个class对象。
(2)链接。链接分三步:校验、准备、解析(非必需)。
(3)初始化。初始化静态变量并执行静态域代码。
上文提到的点,当访问一个类的静态常量属性时,类的初始化工作并不会进行,真正的初始化工作被延迟到对静态方法或者非常量静态属性的首次访问时。(初始化有效实现尽可能的惰性,以此减少不必要内存使用)

4.类加载器
JVM使用三种类加载器,bootstrap类加载器,extension类加载器,system类加载器。三个加载器为父子关系,bootstrap在最顶端,system在最底层。
其中:(1)bootstrap类加载器用于引导JVM,一旦调用java.exe程序,bootstrap类加载器就开始工作。因此必须使用本地代码实现,然后加载JVM 需要的类到函数中。另外,它还负责加载所有的Java核心类,例如java.lang和java.io包,还会查找核心类库如tr.jar、i18n.jar等,这些类库根据JVM和操作系统来查找。
(2)extension类加载器负责加载标准扩展目录下面的类。这样可以使得编写程序变得简单,只需把JAR文件复制到扩展目录下即可,类加载器自动在下面查找。不同供应商提供的扩展类库不同,Sun公司的JVM标准扩展目录是/jdk/jre/lib/ext.
(3)system类加载器是默认的加载器,它在环境变量CLASSPATH目录下查找相应的类。这样,JVM使用哪个类加载器?答案在于委派模型,这是出于安全原因。注意:每次类需要加载,system类加载器首先调用。但是,它不会马上加载类,相反,它委派该任务给它的父类extension类加载器,extension又委派给其父类bootstrap加载器。因此,bootstrap类加载器总是首先加载类。如果bootstrap类加载器不能找到所需的类,extension类加载器会尝试加载。如果扩展类加载器也失败,system类加载器将会执行任务。如果system类加载器找不到类,会抛出一个java.lang.ClassNotFoundException异常。
另外,java类加载器机制的优势在于可以通过扩展java.lang.ClassLoader抽象类来扩展自己的类加载器。这个知识点以后再介绍。

本文参考
Java高级程序设计一书,徐传运,张扬,王森编著【清华大学出版社】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值