美文网首页
ClassLoader实例

ClassLoader实例

作者: shz_Minato | 来源:发表于2019-01-31 11:52 被阅读17次

一、方法概述

 阐述的方法loadClass、findClass、defineClass。

二、方法阐述

 loadClass

 loadClass在ClassLoader中有两个重载的方法,如下:

//第一处
Class<?> loadClass(String name) throws ClassNotFoundException 

//第二处
Class<?> loadClass(String name, boolean resolve)

 第一处
 该方法只有一个参数,参数的含义就是欲加载的类的二进制名字,该方法的含义就是加载指定二进制名字的类,这个类具体调用的是第二处的重载类,虚拟机调用这个类会解析类引用问题。

 第二处
 参数的含义:name就是欲加载的类的二进制名字,resolve是否解析类引用
 方法含义:加载指定二进制名字的类,该方法的默认加载顺序是

    调用findLoadedClass方法检查欲加载的类是否已经加载
    
    调用父加载器的loadClass,如果父加载器为空,那么就会用系统类加载加载
    
    调用findClass去find类

 如果使用以上的步骤find到了欲加载的类,并且resolve参数为true,那么该方法就会调用resolveClass方法去解析类。
 ClassLoader的子类一般比较倾向于重写findClass方法,而不是此方法。

 findClass

 //该方法的实现为抛出异常,没有具体实现,因此子类需要实现
 protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

 参数含义:name就是欲加载的类的二进制名字。
 方法含义:找到指定名字的class,自定义的类加载器需重写此方法。因为这种方式会符合双亲委托模型,在检查父加载器后,loadingClass方法就会调用此方法。(上述的步骤,因此该方法是虚拟机调用,开发者只需调用loadingClass方法即可)

 defineClass

//name:待定义的类的二进制名字
//b: 包含类信息的字节数组
//off:类信息在数组的开始索引
//len: 类信息的长度
Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError

 方法含义:将字节数组转为一个class实例,在一个类被使用之前,class必须被解析。

三 案例使用

 使用自定义类加载器去加载指定的类

//欲加载的类
//二进制名字:com.minato.jvm.chapter15.People
public class People {
}

//自定义类加载器需继承自ClassLoader
public class MyTest extends ClassLoader {
    private String classLoaderName;
    private String fileExtension = ".class";

    public MyTest(String classLoaderName) {
        this.classLoaderName = classLoaderName;
    }

    public MyTest(ClassLoader parent, String classLoaderName) {
        super(parent);
        this.classLoaderName = classLoaderName;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = getClassData(name);
        return defineClass(null, classData, 0, classData.length);
    }

    public byte[] getClassData(String className) {
        byte[] bytes = null;
        InputStream is = null;
        ByteArrayOutputStream bos = null;

        try {
            is = new FileInputStream(new File(className, fileExtension));
            bos = new ByteArrayOutputStream();

            int ch = 0;
            while ((ch = is.read()) != -1) {
                bos.write(ch);
            }

            bytes = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

   

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
       
        
        MyTest myTest=new MyTest("MyLoader");
      
        Class<?> loadClass = myTest.loadClass("com.minato.jvm.chapter15.People");
        Object instance = loadClass.newInstance();
        System.out.println(instance.getClass().getClassLoader());
        //此时打印的类加载器任然是系统类加载器
        //原因:系统类加载器加载的是项目中的类,People就是项目中的类,
        //按照双亲委托模型:myTest加载类,将任务委托给父加载器(系统类加载器),父加载器发现可以加载,就加载类了,并不需要在给子类去加载。
        //故MyTest的findClass方法不会走
        //同样的道理,只要加载的类不是项目中的类,findClass方法就会走,因为父加载器都不会加载。实例如下
    }
}

 加载的类是非项目中的类,只有自定义的类加载器可以加载

//将People移至桌面
public class MyTest extends ClassLoader {
    private String classLoaderName;
    private String fileExtension = ".class";
    private String path;

    public MyTest(String classLoaderName) {
        super();
        this.classLoaderName = classLoaderName;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public MyTest(ClassLoader parent, String classLoaderName) {
        super(parent);
        this.classLoaderName = classLoaderName;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("findClass invoke: "+name);
        System.out.println("class loader name: "+classLoaderName);
        byte[] classData = getClassData(name);
        return defineClass(null, classData, 0, classData.length);
    }

    public byte[] getClassData(String className) {
        byte[] bytes = null;
        InputStream is = null;
        ByteArrayOutputStream bos = null;

        className=className.replaceAll("\\.","\\\\");
        try {

            File file=new File(this.path,className+fileExtension);

            is = new FileInputStream(file);
            bos = new ByteArrayOutputStream();

            int ch = 0;
            while ((ch = is.read()) != -1) {
                bos.write(ch);
            }

            bytes = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

   
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        MyTest myTest=new MyTest("MyLoader");
        myTest.setPath("桌面路径");
        Class<?> loadClass = myTest.loadClass("com.minato.jvm.chapter15.People");
        Object instance = loadClass.newInstance();
        System.out.println(instance.getClass().getClassLoader());
        System.out.println(instance);
        //打印的类加载器是自定义的MyTest
    }
}

相关文章

网友评论

      本文标题:ClassLoader实例

      本文链接:https://www.haomeiwen.com/subject/soeksqtx.html