实践自定义类加载器

ClassLoader类有如下两个关键方法:

loadClass(String name, boolean resolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象。

findClass(String name):根据二进制名称来查找类。

只重写了findClass来了解如何自定义类加载器以及.java-->.class-->程序运行之间的大概流程

自定义的类加载器代码如下:

CompileClassLoder类

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class CompileClassLoader extends ClassLoader {
    //读取文件
    private byte[] getBytes(String filename) throws IOException {
        File file = new File(filename);
        long len = file.length();
        byte[] raw = new byte[(int) len];
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            //一次读取class全部二进制代码
            int r = fileInputStream.read(raw);
            if (r != len)
                throw new IOException("无法读取全部文件" + r + "!=" + raw);
            return raw;
        }
    }
    // 定义编译指定Java文件的方法
    private boolean compile(String javaFile)throws IOException{
        System.out.println("CompileLoader正在编译"+javaFile+"...");
        Process p=Runtime.getRuntime().exec("javac "+ javaFile); //用javac编译java文件
        //exec:Executes the specified string command in a separate process with the specified environment.
        try {
            p.waitFor();
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        int res =p.exitValue();
        return res==0;
    }
    // 重写ClassLoader的findClass方法
    protected Class<?> findClass(String name) throws ClassNotFoundException{
        Class clazz=null;
        String file=name.replace('.','/');
        String javaFilename=file+".java";
        String classFilename=file+".class";
        File javaFile = new File(javaFilename);
        File classFile =new File(classFilename);
        // 当指定Java源文件存在,且class文件不存在、或者Java源文件
        // 的修改时间比class文件修改时间更晚,重新编译
        if (javaFile.exists()&&(!classFile.exists()
                ||javaFile.lastModified()>classFile.lastModified()))
        {
            try {
                // 如果编译失败,或者该Class文件不存在
                if (!compile(javaFilename)||!classFile.exists()){
                    throw new ClassNotFoundException(
                            "ClassNotFoundException:"+javaFilename
                    );
                }
            }catch (IOException ex){
                ex.printStackTrace();
            }
        }
        // 如果class文件存在,系统负责将该文件转换成Class对象
        if (classFile.exists()){
            try {
                // 将class文件的二进制数据读入数组
                byte[] bytes = getBytes(classFilename);
                // 调用ClassLoader的defineClass方法将二进制数据转换成Class对象
                clazz=defineClass(name,bytes,0,bytes.length);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 如果clazz为null,表明加载失败,则抛出异常
        if (clazz==null){
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

    public static void main(String[] args)throws Exception{
        // 如果运行该程序时没有参数,即没有目标类
        if (args.length<1){
            System.out.println("缺少目标类,请按如下格式运行Java源文件:");
            System.out.println("java CompileClassLoader ClassName");
        }
        // 第一个参数是需要运行的类
        String progClass = args[0];
        // 剩下的参数将作为运行目标类时的参数,
        // 将这些参数复制到一个新数组中
        String[] progArgs=new String[args.length-1];
        System.arraycopy(args,1,progArgs,0,progArgs.length);
        CompileClassLoader ccl=new CompileClassLoader();
        // 加载需要运行的类
        Class<?> clazz = ccl.loadClass(progClass);
        // 获取需要运行的类的主方法
        Method main=clazz.getMethod("main", String[].class);
        Object [] argsArray= {progArgs};
        main.invoke(null,argsArray);
    }

}

测试类Hello:

public class Hello {
    public static void main(String[] args)
    {
        System.out.println(Hello.class.getClassLoader());
    }
}

 由于用的是idea,.java和.class不在一起,所以使用命令行语句生成CompileClassLoader.class文件

javac -encoding UTF-8 CompileClassLoader.java
然后 用指定的类加载器运行Hello.java

java CompileClassLoader Hello

结果:

 中途遇到的问题:

1.java CompileClassLoader Hello时 提示

找不到或无法加载主类 CompileClassLoader

//原因:没有在Hello.java的同级目录中生成CompileClassLoader.class文件
//解决办法
javac CompileClassLoader.java

2.Cannot run program "javacHello.java": CreateProcess error=2, 系统找不到指定的文件

//原因:CompileClassLoader类中 下面语句javac后边少了个空格
// 修改后需要从新编译class文件
Process p=Runtime.getRuntime().exec("javac "+ javaFile); //用javac编译java文件

                
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值