Java的类加载器

时间:2022-07-24
本文章向大家介绍Java的类加载器,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

作用

  • 编译器先把java文件编译成class字节码文件
  • ClassLoad会把字节码文件转换成jvm中的Class对象
  • jvm再把class对象转成实例对象

ClassLoad在java 中有着非常重要的作用,他主要工作是在Class装载的加载过程,他的主要作用是 从系统外部获取二进制数据流。它是java的核心组件,所有的class都是通过ClassLoad进行加载的,ClassLoad负责将class文件里的二进制流输入到系统中交给jvm进行连接,初始化操作。

分类

  1. 系统自带的类加载器
  2. 启动类加载器(BootStrap) c++编写 加载核心库 java.* 3.拓展类加载器 (Extension) java编写 加载拓展库 javax.* 4.应用程序加载类(AppClassLoader)java编写 加载程序所在目录 5.用户自定义的类加载器 自定义类加载器 java编写 定制化加载

我们先了解2个方法

第一个方法 findClass

/**
 
     * Finds the class with the specified <a href="#name">binary name</a>.
 
     * This method should be overridden by class loader implementations that
 
     * follow the delegation model for loading classes, and will be invoked by
 
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
 
     * parent class loader for the requested class.  The default implementation
 
     * throws a <tt>ClassNotFoundException</tt>.
 
     *
 
     * @param  name
 
     *         The <a href="#name">binary name</a> of the class
 
     *
 
     * @return  The resulting <tt>Class</tt> object
 
     *
 
     * @throws  ClassNotFoundException
 
     *          If the class could not be found
 
     *
 
     * @since  1.2
 
     */
 
 protected Class<?> findClass(String name) throws ClassNotFoundException {
 
 throw new ClassNotFoundException(name);
 
 }
 

我大概翻译了一下:

将字节数组转换为类Class的实例。必须先解析Class才能使用。

大白话就是,将字节流转换为类,找不到就报错!子类应该覆盖这个方法 第二个方法 defineClass

protected final Class<?> defineClass(String name, byte[] b, int off, int len,
 
 ProtectionDomain protectionDomain)
 
 throws ClassFormatError
 
 {
 
        protectionDomain = preDefineClass(name, protectionDomain);
 
 String source = defineClassSourceLocation(protectionDomain);
 
 Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
 
        postDefineClass(c, protectionDomain);
 
 return c;
 
 }
 

根据其官方文档,再简化之后我总结了九个字:将字节数组转换为类


模拟一个类,假装这个类是外部文件!我们通过类加载器去加载这个文件!我们通过类加载器创建该实例!他就会打印构造函数中的一句话!废话不多说我们直接上图吧!

/**
 
 * 模拟这个类被加载,我们先把他搞成.class文件  然后,他被加载时就会打印空构造方法!
 
 */
 
public class TestClasssLoader {
 
 public TestClasssLoader() {
 
 System.out.println("Hello ClasssLoader!!!");
 
 }
 
}
 

在本地cmd命令行,通过javac TestClasssLoader.java 编译此文件,会得到一个.class文件,我们将这个class文件随便放个地方!然后开始编写我们自己的类加载器!

package com.zanzan.vo;
 


 
import lombok.AllArgsConstructor;
 


 
import java.io.*;
 


 
/**
 
 * 自定义类加载器
 
 * @author huangfu
 
 * @AllArgsConstructor 是lombok一个插件,他就是生成MyClassLoader的构造方法的!你也可以手动生成
 
 */
 
@AllArgsConstructor
 
public class MyClassLoader extends ClassLoader {
 
 /**
 
     * .class文件所在位置
 
     */
 
 private String path;
 


 
 /**
 
     * 查找类加载器
 
     * @param name 类名(不带.class)
 
     * @return
 
     * @throws ClassNotFoundException
 
     */
 
 @Override
 
 protected Class<?> findClass(String name) throws ClassNotFoundException {
 
 byte[] bytes = new byte[0];
 
 try {
 
 //这里就是为了获取.class文件的字节流
 
            bytes = loadClassFile(name);
 
 } catch (IOException e) {
 
            e.printStackTrace();
 
 }
 
 /**
 
         * 开始加载类
 
         * 四个参数!
 
         * 1.类的名称
 
         * 2. .class文件的字节流
 
         * 3. 从那个位置开始读取
 
         * 4. 读取多长
 
         */
 
 return defineClass(name,bytes,0,bytes.length);
 
 }
 


 
 /**
 
     * 获取.class文件的字节流信息
 
     * @param fileName
 
     * @return
 
     * @throws IOException
 
     */
 
 private byte[] loadClassFile(String fileName) throws IOException {
 
 String pathFile = path+File.separator+fileName+".class";
 
 FileInputStream in = new FileInputStream(pathFile);
 
 ByteArrayOutputStream out = new ByteArrayOutputStream();
 
 int readIndex = -1;
 
 while ((readIndex = in.read())!=-1){
 
            out.write(readIndex);
 
 }
 
        in.close();
 
        out.close();
 
 return out.toByteArray();
 


 
 }
 
}
 

功能测试

终于,我们的代码写完了,我们需要测试一下功能!在测试之前回顾一下java的一个基础!类在被加载的时候,会自动调用空构造函数!所以我们的外部类,一旦被加载就会打印 HelloClasssLoader!!!来吧,试一下吧!

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
 
 MyClassLoader myClassLoader = new MyClassLoader("C:\Users\huangfu\Desktop");
 
 Class<?> testClasssLoader = myClassLoader.findClass("TestClasssLoader");
 
        testClasssLoader.newInstance();
 
 }
 

结果:

Hello ClassLoader!!!
 
Process finished with exit code 0 

搞定收工!赶紧回去试试吧!欢迎关注作者哦!