Java虚拟机ClassLoader知识详解(2)

来源:互联网 发布:知乎一句话 编辑:程序博客网 时间:2024/05/16 15:21

Java虚拟机加载器

Java虚拟机加载器类型

–Java虚拟机自带的加载器
•根类加载器(Bootstrap)
•扩展类加载器(Extension)
•系统类加载器(System)
–用户自定义的类加载器
•java.lang.ClassLoader的子类
•用户可以定制类的加载方式

类加载器并不需要等到某个类被“首次主动使用”时再加载它。JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。类被加载后,就进入连接阶段。连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。
类的验证的内容:
–类文件的结构检查:遵循Java类文件的格式;
–语义检查:确保类本身符合Java语法规定;
–字节码验证:确保字节码流可以被Java虚拟机安全地执行;
–二进制兼容性的验证:确保相互引用的类之间协调一致;
调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
ClassLoader加载类时,采用父亲委托机制,有点是提高系统的安全性,用户自定义的加载器不可能加载一个本应由父加载器加载的类。
如果一个类加载器成功加载一个类,则该类加载器被称为定义类加载器,所有能够返回class对象引用的类加载器(包括定义类加载器)都被称为初始类加载器。
下面是我自定义的加载器:`

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader{

private String name;private String path="d:\\";private final String fileType=".class";public static void main(String[] args) throws Exception {    MyClassLoader loader1 = new MyClassLoader("loader1");    MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");    MyClassLoader loader3 = new MyClassLoader(null,"loader3");    loader1.setPath("D:\\MyClass\\Loader1Class\\");    loader2.setPath("D:\\MyClass\\Loader2Class\\");    loader3.setPath("D:\\MyClass\\Loader3Class\\");    //loader1.loadClass("Person").newInstance();//先loadClass然后实例化(为了调用构造方法中的的输出语句)    loader2.loadClass("Person").newInstance();    loader3.loadClass("Person").newInstance();}public MyClassLoader(String name){    super();//让系统类加载器成为该类加载器的父类加载器    this.name=name;}public MyClassLoader(ClassLoader parent,String name){    super(parent);//显示指定该类加载器的父类加载器    this.name=name;}@Overrideprotected Class<?> findClass(String name) {    // TODO Auto-generated method stub    byte data[] = loadClassDate(name);    if(data!=null){        return this.defineClass(data, 0, data.length);    }    return null;}private byte[] loadClassDate(String name){    InputStream is = null;    byte[] data =null;    ByteArrayOutputStream baos = null;    try {        this.name = this.name.replace(".", "\\");        is = new FileInputStream(new File(path+name+fileType));        baos = new ByteArrayOutputStream();        int ch = 0;        while(-1!=(ch=is.read())){            baos.write(ch);        }        data = baos.toByteArray();    } catch (Exception e) {    }finally{        try {            if(is!=null){                is.close();            }            if(baos!=null){                baos.close();            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    return data;}public String getPath() {    return path;}public void setPath(String path) {    this.path = path;}@Overridepublic String toString() {    // TODO Auto-generated method stub    return this.name;}

}
`

在person类中主动使用dog类

public class Person {    public int i=1;    public Person() {    System.out.println("Person is loaded by "+this.getClass().getClassLoader());        //在person类中主动使用dog类        new Dog();    }}

dog类

public class Dog {    public Dog() {        System.out.println("Dog is loaded by "+this.getClass().getClassLoader());    }}

然后把三个类的class文件放到相应相应的文件夹下,运行结果:

D:\MyClass\syslib>java MyClassLoader
Person is loaded by loader1
Dog is loaded by loader1
Person is loaded by loader3
Dog is loaded by loader3

D:\MyClass\syslib>
由于loader2的父加载器loader1可以加载person和dog类,而loader3的父类加载器系统类加载器和扩展类加载器和根类加载器都不能加载,所以只能有loader3加载。
此处,对三种类加载器的特点、加载路径和加载器的命名空间都没有详细说明,以后有机会再补!

0 0
原创粉丝点击