java 自定义类加载器

百度了一下,通篇全部都是启动类加载器,扩展类加载器,应用程序类加载器,还有就是双亲委托模式 。

可是一圈下来,新手们依然不知道如何自定义一个类加载器,来生动的展现什么是类加载器。

首先我们在E:upload下新建一个a/BB.java文件。

代码如下:

package a;

public class BB {
    private String a;
    public BB(){

    }
    public BB(String a){
        this.a=a;
    }
    public static void main(String[] args) {
         System.out.println("aaaaaaaaaa");
    }

}

 编译后出现BB.class字节码文件

 退回到上级目录,因为包是到a目录的。执行java a.BB;正确执行main方法

现在我们回到IDea编辑器中,将BB.class文件读取到内存,并且利用反射进行实例化。

自定义类加载器   MyClassLoader.java

package a;

import java.io.*;
import java.lang.reflect.Field;

public class MyClassLoader  extends ClassLoader{
    @Override
    protected Class<?> findClass(String name) {
        byte[] bytes=null;
        //将点替换成斜杠
        String fileName=name.replaceAll("\\.","/");
        StringBuilder sb=new StringBuilder("E:");
        sb.append(File.separator);
        sb.append("upload");
        sb.append(File.separator);
        sb.append(fileName);
        sb.append(".class");
        fileName=sb.toString();
        try {
            InputStream is=new FileInputStream(fileName);
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            byte[] buf=new byte[1024];
            int r=0;
            while ((r=is.read(buf))!=-1){
                bos.write(buf,0,r);
            }
            bytes=bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return defineClass(name,bytes,0,bytes.length);
    }

    public static void main(String[] args) throws Exception{
        //自定义类加载器对象1
        MyClassLoader c1=new MyClassLoader();
        String className="a.BB";
        Class clazz1=c1.loadClass(className);

        //自定义类加载器对象2
        MyClassLoader c2=new MyClassLoader();
        Class clazz2=c2.loadClass(className);

        System.out.println(clazz1.getClassLoader());
        System.out.println(clazz2.getClassLoader());

        if(clazz1!=clazz2){
            System.out.println("不同的类加载器对象加载相同的class文件,会产生不同的类对象");
        }
        Object obj1=clazz1.getDeclaredConstructor(new Class[]{String.class}).newInstance("自定义加载器加载进内存的");
        Field fa=clazz1.getDeclaredField("a");
        fa.setAccessible(true);//将私有变量设置成可以访问的权限
        System.out.println(fa.get(obj1));

    }
}

执行结果:

e.MyClassLoader@2b193f2d
e.MyClassLoader@4dc63996
不同的类加载器加载相同的class文件,会产生不同的类对象
自定义加载器加载进内存的

很明显clazz1和clazz2是两个类。

给BB.java中构造器传入的字符串:“自定义加载器加载进内存的”   也在上面打印出来了。

注意:如果将a/BB.java文件拷贝到idea编辑器中。那么MyClassLoader中的findClass就不会执行了。

因为MyClassLoader c1和MyClassLoader c2都会有一个指向上级类加载器的引用,直接交个上级类加载器加载;

应用程序类加载器会首先找到a/BB.class文件,并加入内存;

就不会在继续寻找了。所以自定义的类加载器就不会寻找BB.class文件了。

 

猜你喜欢

转载自www.cnblogs.com/guoyansi19900907/p/12566101.html