菜鸟学JAVA之——类加载

类加载

类加载器(ClassLoader)

什么是类加载器?

就是Java代码在运作,JVM在启动时,把类模板加载到内存去的工具

首先,一个Java程序真正的执行过程应该是你去调用了Java这个命令,然后程序开始执行,而执行的过程中,JVM会将很多类(.class文件,或者.jar文件)加载到当前的程序内存当中。

当你去写 类型 a = new 类型()时,类加载器就会把加载好的模板放到堆中申请空间并占用空间,把东西加载到内存中。

类加载器的分类
在这里插入图片描述
真正获得类模板的过程,是通过一个叫做ClassLoader的工具来获得到的

作用:ClassLoader就是将一个存在于系统文件中的.class文件,加载到当前程序的内存当中,变成JVM中的一个对象、一个类模板,Java语言就可以识别这个Class类型

把类模板加载到工程中

问题:现有一个类的对象和他的.class文件,需要加载出这个类,生成一个对象。

defineClass():把这二进制文件变成我们想要的Class文件

首先自定义一个类加载器,返回的就是由Cent.class文件生成的类模板

public class MyClassLoader extends ClassLoader {
    
    

    /*
        //把从外部看到的.class文件变成内存中,在代码中看到的Class文件(类模板),并且用这个Class来创建对象,这个.class文件在哪不用关心
        defineClass()//第二个参数数组存放的就是.class文件转换成的二进制码的数组,可以把这二进制文件变成我们想要的Class文件

     */

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
    
    
        //找到那个.class文件,用文件流怼到这个文件上
        FileInputStream fis = null;
        try {
    
    
            fis = new FileInputStream("Z:/Cent.class");
            byte[] b = new byte[fis.available()];
            fis.read(b);
            return defineClass(name,b,0,b.length);//defindClass就是定义class的,是ClassLoader给出的
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return super.findClass(name);
    }
}

ObjectInputStream使用了自己的类加载器(应用加载器),并不能加载出我们想要加载的那个类现在需要ObjectInputStream在加载我们的类时使用我们自定义的类加载器,加载其他类时使用自己的类加载器这时就需要继承ObjectInputStream,重写他的resolveClass方法了

重写ObjectInputStream的类加载器

public class MyObjectInputStream extends ObjectInputStream {
    
    

    private ClassLoader classLoader;

    public MyObjectInputStream(InputStream in) throws IOException {
    
    
        super(in);
    }

    public MyObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
    
    
        super(in);
        this.classLoader = classLoader;
    }

    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
    
    
        //如果可以创建对象成功就用的自己的类加载器,如果不成功,就捕获异常,用父类的类加载器创建对象
        try {
    
    
            return Class.forName("baidu.ali.tencent.Cent",false,this.classLoader);//第二个参数initialize:说明这个类是否必须初始化。
            /*
            //当然这里除了上面那样写,也可以像下面这样写,这是下面这样的写法具有局限性,让MyObjectInputStream类加载器只能加载这一种外部的类,不能加载其他类型的外部类
            MyClassLoader loader = new MyClassLoader();
            Class aClass = loader.loadClass("baidu.ali.tencent.Cent");
            return aClass;
            */
        } catch (Exception e) {
    
    
            return super.resolveClass(desc);
        }
    }
    
}
ublic class HomeworkDemo {
    
    
    public static void main(String[] args) {
    
    
        MyClassLoader loader = new MyClassLoader();
        try {
    
    
            Class clazz = loader.loadClass("baidu.ali.tencent.Cent");//用自己定义的类加载器拿到了类模板了,加载的只是一个类型,还并不是对象
            
            /*
            ObjectInputStream使用了自己的类加载器(应用加载器),他只能加载写在工程里的类,并不能加载出我们想要加载的那个类
            现在需要ObjectInputStream在加载我们的类时使用我们自定义的类加载器,加载其他类时使用自己的类加载器
            这时就需要继承ObjectInputStream,重写他的resolveClass方法了
             */
            ObjectInputStream ois = new MyObjectInputStream(new FileInputStream("Z:/object.lgc"),loader);//用loader把类型加载出来
            Object object = ois.readObject();//成功的将外部我们想要加载的类加载进来了,生成了object对象


        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

Guess you like

Origin blog.csdn.net/ysf15609260848/article/details/104465412