类的主动使用与被动使用;ClassLoader的剖析

来源:互联网 发布:淘宝鞋店名字大全 编辑:程序博客网 时间:2024/04/29 21:17

 1.      类的主动使用与被动使用

以下是视为主动使用一个类,其他情况均视为被动使用!

1):初学者最为常用的new一个类的实例对象(声明不叫主动使用)

2):对类的静态变量进行读取、赋值操作的。

3):直接调用类的静态方法。

4):反射调用一个类的方法。

5):初始化一个类的子类的时候,父类也相当于被程序主动调用了(如果调用子类的静态变量是从父类继承过来并没有复写的,那么也就相当于只用到了父类的东东,和子类无关,所以这个时候子类不需要进行类初始化)。

6):直接运行一个main函数入口的类。

所有的JVM实现(不同的厂商有不同的实现,有人就说IBM的实现比Sun的要好……)在首次主动调用类和接口的时候才会初始化他们。

 

 

2.      ClassLoader的剖析

ClassLoader的loadClass方法加载一个类不属于主动调用,不会导致类的初始化。如下代码块

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

Class<?> clazz = classLoader.loadClass("test01.ClassDemo");

并不会让类加载器初始化test01.ClassDemo,因为这不属于主动调用此类。

ClassLoader的关系:

根加载器——》扩展类加载器——》应用类加载器——》用户自定义类加载器

加载类的过程是首先从根加载器开始加载、根加载器加载不了的,由扩展类加载器加载,再加载不了的有应用加载器加载,应用加载器如果还加载不了就由自定义的加载器(一定继承自java.lang. ClassLoader)加载、如果自定义的加载器还加载不了。而且下面已经没有再特殊的类加载器了,就会抛出ClassNotFoundException,表面上异常是类找不到,实际上是class加载失败,更不能创建该类的Class对象。

若一个类能在某一层类加载器成功加载,那么这一层的加载器称为定义类加载器。那么在这层类生成的Class引用返回下一层加载器叫做初始类加载器。因为加载成功后返回一个Class引用给它的服务对象——也就是调用它的类加载器。考虑到安全,父委托加载机制。

ClassLoader加载类的原代码如下

    protected synchronized Class<?> loadClass(String name,boolean resolve)

    throws ClassNotFoundException

    {

    // First, check if the class has already been loaded

    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.

            c = findClass(name);

        }

    }

    if (resolve) {

        resolveClass(c);

    }

    return c;

    }

初始化系统ClassLoader代码如下

    private static synchronized void initSystemClassLoader() {

    if (!sclSet) {

        if (scl !=null)

       throw new IllegalStateException("recursive invocation");

            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();

        if (l !=null) {

       Throwable oops = null;

       scl = l.getClassLoader();

            try {

           PrivilegedExceptionAction a;

           a = new SystemClassLoaderAction(scl);

                    scl = (ClassLoader) AccessController.doPrivileged(a);

            } catch (PrivilegedActionException pae) {

           oops = pae.getCause();

                if (oopsinstanceof InvocationTargetException) {

               oops = oops.getCause();

           }

            }

       if (oops !=null) {

           if (oopsinstanceof Error) {

           throw (Error) oops;

           } else {

               // wrap the exception

               throw new Error(oops);

           }

       }

        }

        sclSet = true;

    }

    }

它里面调用了很多native的方法,也就是通过JNI调用底层C++的代码。

3.      当一个类被加载、连接、初始化后,它的生命周期就开始了,当代表该类的Class对象不再被引用、即已经不可触及的时候,Class对象的生命周期结束。那么该类的方法区内的数据也会被卸载,从而结束该类的生命周期。一个类的生命周期取决于它Class对象的生命周期。由Java虚拟机自带的默认加载器(根加载器、扩展加载器、系统加载器)所加载的类在JVM生命周期中始终不被卸载。所以这些类的Class对象(我称其为实例的模板对象)始终能被触及!而由用户自定义的类加载器所加载的类会被卸载掉!