03-类加载器

03-类加载器

类加载器

    

    类加载定义:通过一个类的全限定名来获取描述此类的二进制流来获取所需要的类的动作
        
    类从被加载到虚拟机内存中开始,到卸载出内存生命周期分为以下7个阶段
        加载(Loading) -> 【验证(Verification) -> 准备(Preparation) -> 解析(Resolution)】 -> 初始化(Initialization) -> 使用(Using) -> 卸载(Unloading)
        验证、准备和解析统称为连接(Linking)
    
    主动引用(会触发类初始化的引用):
        1.遇到new,getstatic,putstatic或invokestatic这4条指令时,若类没有初始化会被触发初始化(new对象时、读取或者设置类静态非常量字段时、调用类静态方法)
        2.反射调用类时
        3.初始化类,其父类还未被初始化时触发父类初始化
        4.虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的那个类),虚拟机会先初始化这个类

    被动引用(不会触发类初始化的引用):
        1.通过子类引用父类的静态字段
        2.通过定义数组来引用类
        3.在A类中用到了B类的静态常量,这里B类不会被初始化。常量在编译阶段会存到调用类的常量池中,本质上没有直接调用定义常量的类
        
    双亲委派模型:
        1.虚拟机的角度看类加载器种类:

             
  a.启动类加载器(Bootstrap ClassLoader),用C++实现。
             
  b.所有的其他类加载器,都由Java实现。并且都继承于java.lang.ClassLoader类

        2.开发人员的角度看类加载器种类:
             
  a.启动类加载器(Bootstrap ClassLoader):负责加载/lib目录下。(按照文件名识别)

             
  b.扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载/lib/ext目录中的,或者被java.ext.dirs系统变量所指定的路径中所有的类库

             
  c.应用程序类加载器(Application ClassLoader):这个类加载器由sun.misc.Launcher$AppClassLoader实现,由于ClassLoader的getSystemClassLoader方法返回值也是它,所以一般它也被称为系统加载器。


        工作过程:
            如果一个类收到了类加载的请求,它首先不会自己去尝试去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。
    因此所有的类加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
    
       双亲委派模型带来的好处:
            1.[稳定性]同一个类始终会给同一个类加载器去加载,例如java.lang.Object在rt.jar中。那么在各种类加载器环境中都会是委派给启动类加载器,所以系统中也只会有一个Objec类
    

         ClassLoader实现双亲委派模型源码:

/**
*使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类: 
1.调用 findLoadedClass(String) 来检查是否已经加载类。
2.在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 
3.调用 findClass(String) 方法查找类。
如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。 
鼓励用 ClassLoader 的子类重写 findClass(String),而不是使用此方法,ClassLoader的findClass方法默认是抛出ClassNotFoundException

**/ 
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);
                    // 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;
        }
    }

版权声明:本文为博主原创文章,未经博主允许不得转载。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注