Java ClassLoader学习笔记

ClassLoader的作用:

  • 负责将 Class 加载到 JVM 中
  • 审查每个类由谁加载(父优先的等级加载机制), 系统内置的ClassLoader通过双亲委托来加载指定路径下的class和资源
  • 将 Class 字节码重新解析成 JVM 统一要求的对象格式
  • 可以自定义ClassLoader一般覆盖findClass()方法。
  • ContextClassLoader与线程相关,可以获取和设置,可以绕过双亲委托的机制。

 

初始化阶段虚拟机规范是严格规定了如下几种情况,如果类未初始化会对类进行初始化:

1. 创建类的实例
2. 对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化
3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main 方法的那个类),虚拟机会先初始化这个主类
5. 当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。

不会初始化的几种易搞错的情况:

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

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

特别需要指出的是,类的实例化与类的初始化是两个完全不同的概念:

  • 类的实例化是指创建一个类的实例(对象)的过程;
  • 类的初始化是指为类中各个类成员(被static修饰的成员变量)赋初始值的过程,是类生命周期中的一个阶段。

双亲委托:可以避免重复加载,当父亲已经加载了该类的时候,就没有必要 ClassLoader再加载一次。安全好,不会被替换。

ClassLoader使用的是双亲委托机制来搜索加载类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个组合的关系

先检查是否已经被加载过,若没有加载则调用父加载器的loadClass() 方法,若父加载器为空,则默认使用启动类加载器作为父加载器。如果父加载器失败,再调用自己的findClass 方法进行加载,因此到这里再次证明了类加载器的过程:

 

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
// 先委派给父类加载器加载
                        c = parent.loadClass(name, false);
                    } else {
   //如果父加载器不存在,则委托给启动类加载器 加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

// 如果父类加载器无法加载,自身才尝试加载. 自定义加载的时候,由于parent == null, class文件不在启动加载器的路径里面。所以最后还是调用到findClass方法里来了。所以 自定义的时候只要重写findClass方法就可以了。
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                }
            }
            return c;
    }

 

类的唯一性:

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间

自定义ClassLoader:

继承ClassLoader类,实现findClass方法。

假设我们需要一个自定义的classloader,默认加载路径为D:\lib下的jar包和资源。

Context ClassLoader 线程上下文类加载器

contextClassLoader是Thread类的成员变量,通过setContextClassLoader()方法设置,通过getContextClassLoader()获得。  

每个Thread都有一个相关联的ClassLoader,默认是AppClassLoader。并且子线程默认使用父线程的ClassLoader除非子线程特别设置。

参考:

https://blog.csdn.net/u014634338/article/details/81434327

https://segmentfault.com/a/1190000013469223

https://www.cnblogs.com/faunjoe88/p/8023239.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值