美文网首页java 数据结构jvm
java:类的加载机制(二)

java:类的加载机制(二)

作者: 过期的薯条 | 来源:发表于2017-06-16 20:29 被阅读14次

    1.引言

    写简书,第一次觉得好想去分享知识。也体会到知识带给我的充实感,相信自己这样下去,2年之后一定能达到我的目标。java类加载机制主要还是看的这篇博客 深入理解java类加载器。这个原文作者真的是太厉害了。写的很详细,我也很有收获。

    2.正题

    前面说了一个类的生命周期:

    Paste_Image.png

    加载的过程是将二进制的class文件。放进堆中,在堆中形成一个Class对象。这个过程需要用到3种类加载器。

    启动(Bootstrap)类加载器:

    主要加载jdk中jre/lib/rt.jar中的类。具体加载的那些文件,那些jar包可以自己解压看看。

    扩展(Extension)类加载器:

    扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。加载jre/lib/ext/*.jar

    系统(System)类加载器:

    系统类加载器是由 Sun的 :AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。加载
    classpath指定的jar或者目录。(我理解就是项目中的jar,或者java文件)

    这三个加载的关系是:是系统类加载器的父类加载器是标准扩展类加载器,标准扩展类加载器的父类加载器是启动类加载器

    Paste_Image.png

    代码证明:

    public class LoaderTest {  
      
        public static void main(String[] args) {  
            try {  
                System.out.println(ClassLoader.getSystemClassLoader());  
                System.out.println(ClassLoader.getSystemClassLoader().getParent());  
                System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
    

    输出的结果是:

    sun.misc.Launcher$AppClassLoader@6d06d69c  
    sun.misc.Launcher$ExtClassLoader@70dea4e  
    null  
    

    第三个输出的结果:之所以是为null。是因为Bootstrap是C启动生成的对象。(暂时这样理解,可能不准确,没深究这个东西)。

    类加载的算法:

    双亲委派: 通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

    源码分析:

     protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // 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
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);//依旧为null,那么自己开始加载
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    

    这段代码结合debug模式,很容易懂,上面标注了一下注释。

    Class.forName

    Class.forName 我第一次接触是在数据库的学习载入驱动,当时不懂为什么要这样搞,只知道需要,然而现在懂了。Class.forName 就是调用加载器加载类,从而在堆中形成一个Class对象。Class.forName(String name)默认会使用调用类的类加载器来进行类加载。

    现在做一个测试:验证下上面提到的结论:

    扩展(Extension)类加载器,加载jre/lib/ext/*.jar;AppClassLoader加载
    classpath指定的jar或者目录。

    demo1.gif

    将Test的class打包的gif图:

    demo2.gif

    打包完毕将其放在jre/lib/ext/下面。新建一个项目,这个时候就会看到test.jar 出现在project 下面的External Libraries中。(提示:可能一次还加载不出来,要确确实实的关闭了jvm,这样下次才会出现)。

    之后再运行:可以很清晰的看到出来的是Extension类加载器。

    demo3.gif

    从结果可以看出上面的结论没有错。。明天再写下自定义加载器等知识点,做一下笔记。

    相关文章

      网友评论

        本文标题:java:类的加载机制(二)

        本文链接:https://www.haomeiwen.com/subject/ypmmqxtx.html