JVM7(ClassLoader源码解读,写自定义类加载器)

JVM7(ClassLoader源码解读,写自定义类加载器)_第1张图片

数组的类型实在程序运行时生成的,它的类加载器是和它里面的元素的类加载器是一样的。但基本数据类型是没有类加载器的,这时的数组也是没有类加载器的,为null.

自定义ClassLoader:

public class Test6 {

    public static void main(String[] args) throws Exception {
        MyClassLoader c = new MyClassLoader("myClassLoader");
        Class clazz = c.loadClass("com.hk.Test4");
        Object o =clazz.newInstance();
        System.out.println(o.toString());
    }
}


class MyClassLoader extends ClassLoader {


    private final String classLoaderName;

    private static final String extension = ".class";


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

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

    @Override
    protected Class findClass(String className) {
        byte[] bytes = loadClassData(className);
        return this.defineClass(className, bytes, 0, bytes.length);
    }

    private byte[] loadClassData(String className) {
        InputStream inputStream = null;
        BufferedInputStream bufferedInputStream = null;
        StringBuffer buffer = new StringBuffer();
        try {
            inputStream = new FileInputStream(className + extension);
            bufferedInputStream = new BufferedInputStream(inputStream);
            byte[] bytes = new byte[1024];
            int len;
            while ((len=bufferedInputStream.read(bytes))!=-1) {
                buffer.append(bytes);
            }
            /*ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int i;
            while ((i=inputStream.read())!= -1) {//返回的读到的一字节数据
                byteArrayOutputStream.write(i);
            }
            return byteArrayOutputStream.toByteArray();*/

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedInputStream != null) {
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            return buffer.toString().getBytes();
        }
    }

    @Override
    public String toString() {
        return "[this is " + classLoaderName + "]";
    }
}

loadClass () —— findClass()(需要重写) —— defineClass() 方法调用顺序

JVM7(ClassLoader源码解读,写自定义类加载器)_第2张图片
JVM7(ClassLoader源码解读,写自定义类加载器)_第3张图片

用自定义加载器加载项目里的类是不起作用的,不会执行自定义加载器的findClass方法,因为双亲委托机制,系统类加载器在项目能找到并可以加载,所以由系统类加载器加载。如果所加载的类不在项目里,而是在其他位置,这时系统类加载器找不到,自定义加载器能找到的前提下,才由自定义类加载进行加载。

系统类加载多次加载同一个类,只会加载一次,会返回同一个class对象。因为系统类加载器只有一个命名空间。自定义类加载器的不同对象有不同的命名空间,一个对象只会加载一次同一个类,多次加载会返回同一个对象。不同自定义类加载器的对象加载同一个类,会产生多个class对象(对象后面的hashcode不一样)因为每个自定义加载器对象都有一个自己的命名空间。总结:不同类加载对象有不同的命名空间,同一个命名空间对同一个类只会有一个class对象。不同的命名空间有对同一个类会有不同的class对象。

JVM7(ClassLoader源码解读,写自定义类加载器)_第4张图片

一个类由哪个加载器加载成功了,那么它里面没有加载的类就由这个加载器为开始进行加载。

子加载器加载的类能够访问父加载器所加载的类,父加载器所加载的类不能够访问子加载器所加载的类。

JVM7(ClassLoader源码解读,写自定义类加载器)_第5张图片
JVM7(ClassLoader源码解读,写自定义类加载器)_第6张图片
-xx:+TraceClassUnloading 打印类的卸载信息,配合System.gc()使用

你可能感兴趣的:(JVM)