java 数据结构jvm

java:类的加载机制(二)

2017-06-16  本文已影响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

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

上一篇下一篇

猜你喜欢

热点阅读