Java基础之自定义类加载器

网友投稿 246 2023-01-15

Java基础之自定义类加载器

一、类加载器关系

自定义类加载器

创建一个类继承ClassLoader类,同时重写findClass方法,用于判断当前类的class文件是否已被加载

二、基于本地class文件的自定义类加载器

本地class文件路径

自定义类加载器:

//创建自定义加载器类继承ClassLoader类

public class MyClassLoader extends ClassLoader{

// 包路径

private String Path;

// 构造方法,用于初始化Path属性

public MyClassLoader(String path) {

this.Path = path;

}

// 重写findClass方法,参数name表示要加载类的全类名(包名.类名)

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

System.out.println("findclass方法执行");

// 检查该类的class文件是否已被加载,如果已加载则返回class文件(字节码文件)对象,如果没有加载返回null

Class> loadedClass = findLoadedClass(name);

// 如果已加载直接返回该类的class文件(字节码文件)对象

if (loadedClass != null){

return loadedClass;

}

// 字节数组,用于存储class文件的字节流

byte[] bytes = null;

try {

// 获取class文件的字节流

bytes = getBytes(name);

} catch (Exception e) {

e.printStackTrace();

}

if (bytes != null){

// 如果字节数组不为空,则将class文件加载到JVM中

System.out.println(bytes.length);

// 将class文件加载到JVM中,返回class文件对象

Class> aClass = this.defineClass(name, bytes, 0, bytes.length);

return aClass;

}else {

throw new ClassNotFoundException();

}

}

// 获取class文件的字节流

private byte[] getBytes(String name) throws Exception{

// 拼接class文件路径 replace(".",File.separator) 表示将全类名中的"."替换为当前系统的分隔符,File.separator返回当前系统的分隔符

String FileUrl = Path + name.replace(".", File.separator) + ".class";

byte[] bytes;

// 相当于一个缓存区,动态扩容,也就是随着写入字节的增加自动扩容

ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();

File file = new File(FileUrl);

// 创建输入流

InputStream inputStream = new FileInputStream(file);

int content;

// 循环将输入流中的所有数据写入到缓存区中

while ((content = inputStream.read()) != -1){

arrayOutputStream.write(content);

arrayOutputStream.flush();

}

bytes = arrayOutputStream.toByteArray();

return bytes;

}

}

测试类

三、遇到的问题

在获取class文件字节流的getBytes方法中,为什么不将输入流中的所有数据直接写入到bytes中,而是要先写入到ByteArrayOutputStream中?如下:

现在我们尝试将数据直接写入到bytes中,如下:

但在运行时报错:

Extra bytes at the end of class file com/smallsweets/OutSide

这是为什么呢?个人理解如下:

看报错提示Extra bytes at the end of:在文件的最后有多余的字节

查看class文件的大小

但是字节数组在初始化时指定的大小是1024,多余位置的字节是0,所以就出现了多余字节的情况

解决方法是:我们可以在初始化数组时将数组的大小指定为和class文件相同大小,如下:

四、基于网络(url)class文件的自定义类加载器

class文件路径

自定义类加载器:

public class MyUrlClassLoader extends ClassLoader {

private String Path;

public MyUrlClassLoader(String path) {

this.Path = path;

}

// 参数name表示全类名(包名.类名)

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

// 判断该类的class文件是否已加http://载,已iYfzIxIe加载直接返回class文件对象,没有加载返回null

Class> loadedClass = this.findLoadedClass(name);

if (loadedClass != null){

return loadedClass;

}

byte[] bytes = null;

try {

// 获取网络class文件的字节数组

bytes = getBytes(Path);

} catch (Exception e) {

e.printStackTrace();

}

// 如果字节数组不为空,将class文件加载到JVM中

if (bytes != null){

// 将class文件加载到JVM中,参数(全类名,字节数组,起始位置,长度)

Class> aClass = this.defineClass(name, bytes, 0, bytes.length);

return aClass;

}else {

throw new ClassNotFoundException();

}

}

// 获取网络class文件的字节流,参数为class文件的url

private byte[] getBytes(String fileUrl) throws Exception {

byte[] bytes;

// 创建url对象

URL url = new URL(fileUrl);

HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

// 连接url

httpURLConnection.connect();

// 创建输入流,获取网络中class文件的字节流

InputStream inputStream = httpURLConnection.getInputStream();

// 相当于缓存区,动态扩容

ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();

int content;

// 循环将输入流中的所有数据写入到缓存区中

while ((content = inputStream.read()) != -1){

arrayOutputStream.write(content);

arrayOutputStream.flush();

}

bytes = arrayOutputStream.toByteArray();

return bytes;

}

}

测试类

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:中铁物流查询(中铁物流查询南京几天能到七台河)
下一篇:天气免费API接口到县级(天气API接口)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~