自定义ClassLoader

最近在做一个工作,把两个文件合并,Android中的两个R.java文件合并。看到这个需求时,想到两种方法: 1)逐行读文件,根据关键字区分哪些是内部类,哪些是内部类的成员变量;2)通过将.java文件编译并加载,通过反射得到内部类,和成员变量。第二种方法更直接一些,本文记录下编译并加载.java文件的方法和问题。

目的:编译并加载磁盘上任意位置的.java文件。

实现MyClassloader,继承自ClassLoader,重写findClass方法

package com.demo.RMerger;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassloader extends ClassLoader {
	private String mPre;

	public MyClassloader(String pre) {
		mPre = pre;
	}

	// 读取一个文件的内容
	private byte[] getBytes(String filename) throws IOException {
		FileInputStream fi = null;
		fi = new FileInputStream(filename);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buffer = new byte[8192];
		int read;
		while ((read = fi.read(buffer)) > 0)
			baos.write(buffer, 0, read);
		byte[] classBytes = baos.toByteArray();
		return classBytes;
	}

	// 定义编译指定Java文件的方法
	public boolean compile(String javaFile) throws IOException {
		System.out.println("CompileClassLoader:正在编译" + javaFile + "...");
		// 调用系统的javac命令
		Process p = Runtime.getRuntime().exec("javac " + javaFile);
		try {
			p.waitFor();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 获取javac线程的退出值
		int ret = p.exitValue();
		// 返回编译是否成功
		return ret == 0;
	}

	// 重写ClassLoader的findClass方法
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		Class clazz = null;
		// 将包路径中的点替换成斜线
		String fileStub = name.replace(".", File.separator);
		String javaFilename = mPre + fileStub + ".java";
		String classFilename = mPre + fileStub + ".class";
		File javaFile = new File(javaFilename);
		File classFile = new File(classFilename);
		if (javaFile.exists() && (!classFile.exists()
				|| javaFile.lastModified() > classFile.lastModified())) {
			try {
				// 如果编译失败,或者该Class文件不存在
				if (!compile(javaFilename) || !classFile.exists()) { // 这一步compile重新编译了一次
					throw new ClassNotFoundException("ClassNotFoundException:" +
							javaFilename);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 如果Class文件存在,系统负责将该文件转换成Class对象
		if (classFile.exists()) {
			try {
				// 将Class文件的二进制数据读入数组
				byte[] raw = getBytes(classFilename);
				// 调用ClassLoader的defineClass方法将二进制数据成Class对象
				clazz = defineClass(name, raw, 0, raw.length);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 如果clazz为null,则表明加载失败,抛出异常
		if (clazz == null) {
			throw new ClassNotFoundException(name);
		}
		return clazz;
	}
}
调用方法:

MyClassloader myClassloader = new MyClassloader(System.getProperty("user.dir") + File.separatorChar + pre
				+ File.separatorChar);
Class<?> R = myClassloader.loadClass(name.replace(File.separatorChar, '.'));


   
 注意调用loadClass时候需要用包名+类名;比如com.android.R。 

System.getProperty("user.dir")表示当前工程的路径。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值