类加载机制_双亲委派模型

来源:互联网 发布:tfboys官方周边淘宝店 编辑:程序博客网 时间:2024/05/18 01:45

类加载机制的第一步执行的是类的加载过程,完整的类加载机制包括加载、连接和初始化,其中连接又可以分为验证、准备和解析三个小过程,除了解析过程支持动态绑定发生的时间可能在初始化之后,其他过程按照顺序发生(时间上可重叠)。

类的加载是指将表示类信息的二进制字节流转化为虚拟机中以Class对象为代表的数据结构。

虚拟机中采用双亲委派模型来表现类的加载结构,JVM中预定义的有三种类型的类加载器:

1.启动类加载器(Bootstrap ClassLoader)。由C++代码编写的虚拟机自带的类加载器,负责%JAVA_HOME%/lib目录中或-Xbootclasspath中参数指定的路径中的类

2.扩展类加载器(Extension ClassLoader)。由Sun实现的ExtClassLoader(sun.misc.Launcher$ExtClassLoader),负责%JAVA_HOME%/lib/ext或java.ext.dir目录下的类

3.应用程序类加载器(Application ClassLoader)。由Sun实现的AppClassLoader(sun.misc.Launcher$AppClassLoader),负责%CLASSPATH%中的类,也是程序中默认的类加载器

双亲委派模型是指,除了启动类加载器之外,每个类加载器都有自己的父类加载器,通过组合的方式来复用父类加载器。当一个类加载器收到加载某个类请求的时候,首先检查自己是否已经加载过该类,如果没有则将请求传给父类加载器,直到启动类加载器,父类加载器不能加载再执行自己的类加载过程。

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) {//并且父类不为null,即当前类加载器不为启动类加载器                        c = parent.loadClass(name, false);//则调用父类加载器的loadClass方法                    } 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);//则使用自身的findClass加载该类                    // 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;        }    }
因为虚拟机中的类的唯一性,是根据类和加载类的类加载器一起确定的,所以使用带有层级结构的双亲委派模型,可以保证一定的安全性,例如对于Object类,无论执行加载时选择的哪个类加载器,最后都会由启动类加载器来完成加载,从而可以保证了类的一致性,并且使用相同的类加载器加载同一个类,可以防止生成多个不同的类对象,避免多次加载。

关于类加载器的示例:

public static Unsafe getUnsafe() {/*Unsafe类作为单例模式的一种使用方式,其构造方法为私有的,并且不能通过getUnsafe()方法返回实例对象,因为getUnsafe被设计只能从启动类加载器加载*///得到调用该方法的Class对象Class cc = Reflection.getCallerClass();//判断调用该方法的类是否是引导类加载器(bootstrap class loader)//如果不是的话,比如由AppClassLoader调用该方法,则抛出SecurityException异常if (cc.getClassLoader() != null)throw new SecurityException("Unsafe");//返回单例对象return theUnsafe;}

参考:

《深入理解java虚拟机》

http://www.cnblogs.com/chenpi/p/5389254.html




0 0
原创粉丝点击