Java自定义类的加载器

系列文章目录



前言

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。
在这里插入图片描述


Java程序在运行的时候,JVM通过类加载机制(ClassLoader)把class文件加载到内存中,只有class文件被载入内存,才能被其他class引用,使程序正确运行起来.

Java中的ClassLoader有三种:Bootstrap ClassLoader 、Extension ClassLoader、App ClassLoader。

  1. Bootstrap ClassLoader

由C++写的,由JVM启动.

启动类加载器,负责加载java基础类,对应的文件是%JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等

2.Extension ClassLoader

Java类,继承自URLClassLoader 扩展类加载器,

对应的文件是 %JRE_HOME/lib/ext 目录下的jar和class等

3.App ClassLoader

Java类,继承自URLClassLoader 系统类加载器,

对应的文件是应用程序classpath目录下的所有jar和class等

Java的加载机制是双亲委派机制来加载类

为什么要使用这种方式?这个是为了保证 如果加载的类是一个系统类,那么会优先由Bootstrap ClassLoader 、Extension ClassLoader先去加载,而不是使用我们自定义的ClassLoader去加载,保证系统的安全!

系统的ClassLoader只会加载指定目录下的class文件,如果你想加载自己的class文件,那么就可以自定义一个ClassLoader。

新建一个类继承自java.lang.ClassLoader,重写它的findClass方法,然后将class字节码数组转换为Class类的实例,调用loadClass方法即可。

新建一个样品Java文件,并生成class,然后拷贝到指定目录

package com.javacui.test;
 
public class ClassLoaderTest {
    public static void main(String[] args) {
        System.out.println("I am ClassLoaderTest");
        for (String str : args){
            System.out.println("参数:" + str);
        }
    }
}

自定义一个类加载器,加载该class文件并调用main方法

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
 
public class MyClassLoader extends ClassLoader {
    public static void main(String[] args) throws Exception {
        //这个类class的路径
        String classPath = "D://temp/ClassLoaderTest.class";
        //类的全称,有包名的加包名
        String packageNamePath = "com.javacui.test.ClassLoaderTest";
 
        MyClassLoader myClassLoader = new MyClassLoader(classPath);
        //加载ClassLoaderTest类的class文件
        Class<?> myclass = myClassLoader.loadClass(packageNamePath);
        System.out.println("类加载器是:" + myclass.getClassLoader());
        //利用反射获取main方法
        Method method = myclass.getDeclaredMethod("main", String[].class);
        Object object = myclass.newInstance();
        String[] arg = {"java小强", "博客"};
        method.invoke(object, (Object) arg);
    }
 
    //指定路径
    private String path;
 
    public MyClassLoader(String classPath) {
        path = classPath;
    }
 
    /**
     * 重写findClass方法
     *
     * @param name 是我们这个类的全路径
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class myclass = null;
        // 获取该class文件字节码数组
        byte[] classData = getData();
        if (classData != null) {
            // 将class的字节码数组转换成Class类的实例
            myclass = defineClass(name, classData, 0, classData.length);
        }
        return myclass;
    }
 
    /**
     * 将class文件转化为字节码数组
     */
    private byte[] getData() {
        File file = new File(path);
        if (file.exists()) {
            FileInputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(file);
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int size = 0;
                while ((size = in.read(buffer)) != -1) {
                    out.write(buffer, 0, size);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        } else {
            return null;
        }
    }
}

输出

类加载器是:sun.misc.Launcher$AppClassLoader@14dad5dc
I am ClassLoaderTest

如果想要保护你的class文件,那可以借助自定义类加载器,因为java的class文件是可以被轻易反编译的。

例如上面,我们生成class文件后,可以通过对称加密等方式进行加密,那么拿到的class字节都是加密后,是无法使用的,在上面的getData()方法中我们读取到了文件字节流,可以把该字节流再进行解密。

DES加密使用入门 http://www.javacui.com/java/17.html

JAVA加密算法实现用例 密钥一致协议 http://www.javacui.com/Theory/273.html

JAVA加密算法实现用例 数字签名 http://www.javacui.com/java/312.html

在这里插入图片描述

### 回答1: Java自定义类加载器的一个简单的示例代码如下: public class MyClassLoader extends ClassLoader { public Class<?> findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection } } ### 回答2: Java自定义类加载器代码样例如下: ```java import java.io.*; public class MyClassLoader extends ClassLoader { private String path; // 类加载器加载的路径 public MyClassLoader(String path) { this.path = path; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] data = loadClassData(name); return defineClass(name, data, 0, data.length); } private byte[] loadClassData(String name) { try { FileInputStream fis = new FileInputStream(new File(path + name + ".class")); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len; while ((len = fis.read()) != -1) { baos.write(len); } fis.close(); return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } } ``` 使用自定义类加载器加载: ```java public class Main { public static void main(String[] args) throws Exception { MyClassLoader classLoader = new MyClassLoader("加载路径"); Class<?> clazz = classLoader.loadClass("com.example.TestClass"); // 加载TestClass Object obj = clazz.newInstance(); // 创建TestClass实例 // 使用obj进行操作,调用方法等 } } ``` 以上是一个简单的自定义类加载器的代码样例。我们可以根据实际需求,通过自定义类加载器来实现更复杂的功能,如加载加密/动态生成的文件,实现文件的热加载等。 ### 回答3: 自定义类加载器是指通过继承ClassLoader并重写其中的方法来实现自己的类加载器。下面是一个简单的Java自定义类加载器的代码示例: ```java import java.io.*; public class MyClassLoader extends ClassLoader { // 自定义类加载器需要指定文件的路径 private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 将文件转换成字节流 byte[] data = loadClassData(name); // 调用父的defineClass方法创建对象 return defineClass(name, data, 0, data.length); } private byte[] loadClassData(String className) { try { // 文件的完整路径 String path = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; InputStream inputStream = new FileInputStream(new File(path)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; // 读取文件并写入内存中 while ((length = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, length); } inputStream.close(); outputStream.close(); // 返回字节流 return outputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } public static void main(String[] args) { // 实例化自定义类加载器并指定文件路径 MyClassLoader classLoader = new MyClassLoader("路径"); try { // 使用自定义类加载器加载 Class<?> clazz = classLoader.loadClass("名"); // 可以对加载进行操作 // ... } catch (ClassNotFoundException e) { e.printStackTrace(); } } } ``` 这个自定义类加载器首先需要重写`findClass`方法,在该方法中通过`loadClassData`方法将文件读取为字节流,然后调用父的`defineClass`方法创建对象。 `loadClassData`方法根据指定的文件路径将文件读取为字节流,并将字节流写入ByteArrayOutputStream中,最后返回字节数组。 在示例代码的`main`方法中,实例化自定义类加载器并指定文件路径,然后通过`loadClass`方法加载指定的。可以在加载后对其进行相关操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java毕设王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值