Java类加载器及类的生命周期与初始化过程

一、类加载器是什么?
将class文件预先加载到jvm虚拟机机制。

二、JVM中存在以下三种类加载区
1、根加载器(BootStrap ,C++实现)
2、扩展加载器(Ext ,java实现)
3、系统类加载器(system,java实现)
分别有不同的作用域:
1、根加载器,加载jre之下类文件,如rt.jar出ext文件之外
2、扩展加载器,加载jre/ext之外的类文件
3、系统类加载器,加载App ClassPath指定路径下的类

三、类加载器加载模式
为了保持完整性及一致性,java的类加载机制采用了双亲委派模式进行类加载,
双亲委派模式只的是,在类加载的时候,预先使用指定加载器的父类加载器去加载class文件,当父加载器return空的时候,子加载器才进行加载
BootStrap为最高级别的加载器。

四、自定义类加载器
自定义的类加载器必须继承抽象类ClassLoader然后重写findClass方法,其实他内部还有一个loadClass方法和defineClass方法,另外两种不推荐使用,严重破坏双亲委派模型,
下面代码从网上抄下来的,一个自定义加载器的实现如下:
/**
     * 一、ClassLoader加载类的顺序
     *  1.调用 findLoadedClass(String) 来检查是否已经加载类。
     *  2.在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。
     *  3.调用 findClass(String) 方法查找类。
     * 二、实现自己的类加载器
     *  1.获取类的class文件的字节数组
     *  2.将字节数组转换为Class类的实例
     * @author lei 2011-9-1
     */ 
    public class ClassLoaderTest { 
        public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { 
            //新建一个类加载器 
            MyClassLoader cl = new MyClassLoader("myClassLoader"); 
            //加载类,得到Class对象 
            Class<?> clazz = cl.loadClass("classloader.Animal"); 
            //得到类的实例 
            Animal animal=(Animal) clazz.newInstance(); 
            animal.say(); 
        } 
    } 
    class Animal{ 
        public void say(){ 
            System.out.println("hello world!"); 
        } 
    } 
    class MyClassLoader extends ClassLoader { 
        //类加载器的名称 
        private String name; 
        //类存放的路径 
        private String path = "E:\\workspace\\Algorithm\\src"; 
        MyClassLoader(String name) { 
            this.name = name; 
        } 
        MyClassLoader(ClassLoader parent, String name) { 
            super(parent); 
            this.name = name; 
        } 
        /**
         * 重写findClass方法
         */ 
        @Override 
        public Class<?> findClass(String name) { 
            byte[] data = loadClassData(name); 
            return this.defineClass(name, data, 0, data.length); 
        } 
        public byte[] loadClassData(String name) { 
            try { 
                name = name.replace(".", "//"); 
                FileInputStream is = new FileInputStream(new File(path + name + ".class")); 
                ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
                int b = 0; 
                while ((b = is.read()) != -1) { 
                    baos.write(b); 
                } 
                return baos.toByteArray(); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
            return null; 
        } 
    } 

上面主要记录的是java类加载器,下面记录下一个类的生命周期
类的生命周期为加载、链接(验证、准备、解析)、初始化、使用、卸载5个阶段 
1、类加载,类加载就是上述所说的将类使用类加载器加载到虚拟机中
2、链接(验证、准备、解析)
验证:对装载到jvm的字节码进行验证
a、验证是否虚拟机可读字节码,验证魔数
b、验证字节码与jvm中所支持的版本是否正确,魔数后8个字节码
c、类中的方法等一些列存在是否合法,jvm对class文件的字节码有严格的规则要求
准备:准备阶段,为类中的静态变量分配内存,即放入jvm的方法区的常量池之中,需要注意的是,如果静态变量没有使用final修饰,放入方法区的值是初始值。我们在程序中定义final static int a = 100,则准备阶段中a的初值就是100。
解析:为准备阶段准备好的静态变量符号引用构建引用
3、初始化:初始化有以下4种方式
如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:
通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。
通过反射方式执行以上三种行为。
初始化子类的时候,会触发父类的初始化。
作为程序入口直接运行时(也就是直接调用main方法)。






猜你喜欢

转载自wmhbjb.iteye.com/blog/2210185