NOTE

7.11 自定义类加载器

1. 什么时候需要自定义类加载器 - 加载任意路径(比如非classpath)下的类文件 - 隔离加载类。这样不同应用的同名类都可以加载,比如tomcat 2. 如何自定义类加载器 1. 继承ClassLoader父类 2. 重写父类的方法 1. 如果走双亲委派机制那么重写 findClass 方法

Java创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 什么时候需要自定义类加载器

  • 加载任意路径(比如非classpath)下的类文件
  • 隔离加载类。这样不同应用的同名类都可以加载,比如tomcat

2. 如何自定义类加载器

  1. 继承ClassLoader父类
  2. 重写父类的方法
    1. 如果走双亲委派机制那么重写findClass方法
      1. 读取类文件的字节码
      2. 调用父类的defineClass方法加载类
    2. 如果不走双亲委派机制那么重写loadClass方法
  3. 使用者调用类加载器的loadClass方法

3. 例子

  • 准备一个Java类,编译成class文件
public class MyClass
{
    public MyClass()
    {
        System.out.println("hello, world!");
    }
}
  • 自定义类加载器
public class MyClassLoader extends ClassLoader
{

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException
    {
        MyClassLoader classLoader = new MyClassLoader();

        Class<?> myClass = classLoader.loadClass("MyClass");
        Class<?> myClass2 = classLoader.loadClass("MyClass");

        System.out.println(myClass == myClass2);//true


        myClass.newInstance();//打印hello, world!

        MyClassLoader classLoader2 = new MyClassLoader();
        Class<?> myClass3 = classLoader2.loadClass("MyClass");

        System.out.println(myClass == myClass3);//false.说明类加载器+包名+类名才能唯一确定一个类


    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException
    {
        String path = String.format("C:\\Users\\[user]\\Desktop\\%s.class", name);
        try
        {

            //加载指定路径下的class文件,并转成字节
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Files.copy(Paths.get(path), outputStream);
            byte[] bytes = outputStream.toByteArray();

            //调用父类的defineClass方法
            return defineClass(name, bytes, 0, bytes.length);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            throw new ClassNotFoundException("类文件没有找到", e);
        }
    }
}

4. 参考