jvm类加载机制基础学习笔记

一,类加载机制理解

 (1)概述
 java语言的特性中有一条这样说:Java与C/C++相比更加具有动态性,它能够适应不断发展的环境,库中可以自由地添加新方法和实例变量,而对客户端没有任何影响。再有,当需要将某些代码添加到正在运行的程序中时,动态性将会是一个非常重要的特性。比如:从Internet上下载代码,然后在浏览器上运行。这样的实现技术都是需要凭借Java系统中的类加载机制。
 (2)类加载的过程:将class文件中的二进制数据读入到内存中,并将静态数据转换成方法区中的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.class对象,用来封装在方法区类的对象。类加载子系统示意图如下:
  Class文件加载子系统结构图
 (3)类缓存:标准的JavaSE类加载器可以按要求查找类,并且某个类加载到内存中后将维持一段时间,JVM垃圾收集器可以回收这些Class对象。
  (4)加载类的途径:
  a. 从本地系统直接加载
  b. 通过网络下载.class文件
  c. 从zip,jar等归档文件中加载.class文件
  d. 从数据库中提取.class文件

二,类加载时类成员的加载顺序

java中的类由静态成员和非静态成员组成,在一个类进行加载-初始化的时候顺序是怎么样的呢?
(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;
如果有父类,则顺序是:父类static方法 –> 子类static方法 –> 父类构造方法- -> 子类构造方法

三,类加载器的树状结构

1.Java的类加载器结构

类加载器双亲委派模型(Parents Delegation Model)
注:类加载器的树形继承结构是通过组合的方式实现,而非简单的直接继承实现。

(1)Bootstrap ClassLoader(启动类加载器):负责将存放在JAVA_HOME\jre\lib\rt.jar下的类库加载到虚拟机内存中。启动类加载器是由c,c++实现的,不能被Java代码直接引用,

(2)Extension ClassLoader(扩展类加载器):由sun.misc.Launcher$ExtClassLoader实现,负责加载JAVA_HOME\bin\ext*.jar目录下,或者被java.ext.dirs系统变量指定的路径中的所有类库。可以直接使用扩展类加载器。

(3)Application ClassLoader(系统类加载,应用程序类加载器):由sun.misc.Launcher$AppClassLoader实现。负责加载用户类路径(classpath)上所指定的类库。是应用程序中默认的类加载

获得各层级ClassLoader实例的代码:

ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();//AppClassLoader
ClassLoader extClassLoader = appClassLoader.getParent();//ExtClassLoader
ClassLoader systemClassLoader = extClassLoader.getParent();//SystemClassLoader
//验证:打印引用如下
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@14ae5a5
null

扩展类加载器的父级加载器

2.Android的类加载器结构

Android系统中的类加载器结构.
BootClassLoader:
BaseDexClassLoader
 –>PathClassLoader : 从本地文件系统加载系统类和应用层类,不能从网络加载class字节码
 –>DexClassLoader : 从包含classes.dex文件的.jar或.apk文件中加载class字节码
Anddroid系统的类加载器结构

四,代理模式和双亲委派模型

1.代理模式

2.双亲委派模型

双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,每一个层次的类加载器都是这样工作,因此所有的类加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈无法完成类加载请求时,子类加载器才会尝试自己去加载。
  ClassLoader进行类加载的方法在代码中的实现:

// loadClass:先检查是否已经被加载过,若没有则调用父类加载器的loadClass()方法,
// 若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载器加载失败,则抛出
// ClasNotFoundExceptionyichang,再调用自己的findClass()方法加载
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 先检查要加载的类是否已经被加载,这里说明同一个类只会被加载一次
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                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.
                    //当父类加载器无法加载时,调用自定义的ClassLoader本身的findClass
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

注:同一个类加载器在加载同一个类时不会重复加载,认为是同一个类;不同的类加载器加载同一个类不会认为是同一个类,会重复加载。
可以从代码中看出,只要父类加载能够完成类的加载任务,类加载的工作就会是由父类加载器完成。

扫描二维码关注公众号,回复: 2367243 查看本文章

猜你喜欢

转载自blog.csdn.net/yyg_2015/article/details/80056001