A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 贾振凯 中级黑马   /  2013-3-24 20:38  /  1416 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 贾振凯 于 2013-3-25 18:52 编辑

这个自定义类加载器本来想实现的功能是,当执行java命令式可以通过输入参数来对一个java文件进行自动编译和执行
例如输入如下命令( java MyClassLoderTest Test 参数1 参数2 )的时候可以自动进行Test.java文件的编译并执行Test类的main方法(打印main方法参数),
但是编译的时候总是提示类名出错(见下方),更奇怪的是可以正常产生Test.class文件


******自定义类加载器*************************
public class MyClassLoderTest extends ClassLoader{
//获取字节码文件的内容,并将其封装在字节数组中返回,供defineClass()使用
private byte[] getBytes(String fileName){  
  
  File file = new File(fileName);
  int len = (int)file.length();
  byte[] buf = new byte[len];
  FileInputStream fis = null;
  try {
   fis = new FileInputStream(file);
   if(fis.read(buf)!=len){
    throw new RuntimeException("文件读取异常!");
   }
  } catch (Exception e) {
   e.printStackTrace();
  }finally{
   try {
    if(fis!=null)
     fis.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
  return buf;
}

//对java文件进行编译
private boolean compilePro(String javaFileName) throws IOException{
  System.out.println("MyClassLoder正在编译"+javaFileName+"........");
  Process pro = Runtime.getRuntime().exec("javac "+javaFileName);
  try {
   pro.waitFor();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  int res = pro.exitValue();
  return res==0;
}


@Override         //覆写ClassLoader的findClass方法
protected Class<?> findClass(String name) throws ClassNotFoundException {
  Class<?> clazz = null;
  String fileStub = name.replace('.', '/');//如果包含包名,则将'.'替换成'/'
  String javaFileName = fileStub+".java";
  String classFileName = fileStub+".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{
    if(!compilePro(javaFileName))
     throw new RuntimeException("编译失败");
   }catch(IOException e){
    e.printStackTrace();
   }
  }
  //如果class文件存在,则调用ClassLoader的defineClass()方法获得该文件的Class对象
  if(classFile.exists()){
   byte[] buf = getBytes(classFileName);
   clazz = defineClass(classFileName, buf, 0, buf.length);    //错误提示中 at.....64
  }
  
  if(clazz==null){
   throw new ClassNotFoundException("ClassNotFoundException::"+name);
  }
  return clazz;
}


public static void main(String[] args){
  Class<?> clazz = null;
  if(args.length <1){
   System.out.println("输入参数不正确!");
   return;
  }
  String classFile = args[0];
  MyClassLoderTest mcl = new MyClassLoderTest();
  try {
   clazz = mcl.loadClass("classFile");    //错误提示中   at.....82
   String[] arguments = new String[args.length-1];
   System.arraycopy(args, 1, arguments, 0, args.length-1);
   Method mainM = clazz.getMethod("main", (new String[0]).getClass());
   main.invoke(null, new Object[]{arguments});
   mainM.invoke(null, (Object)arguments );
  } catch (Exception e) {
   e.printStackTrace();
  }
}
}
*****************Test类***********************
public class Test {
public static void main(String[] args) {
  for(String arg : args)
   System.out.println(arg);
}
}




介是怎么啦????????

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

1 个回复

倒序浏览
找来找去终于知道什么问题啦,问题就出在这一行
clazz = defineClass(classFileName, buf, 0, buf.length);    //错误提示中 at.....64

defineClass()方法中二进制文件不可以有.class后缀

API中有这么一段话:
二进制名称
按照《Java Language Specification》的定义,任何作为 String 类型参数传递给 ClassLoader 中方法的类名称都必须是一个二进制名称
有效类名称的示例包括:
  "java.lang.String"
   "javax.swing.JSpinner$DefaultEditor"
   "java.security.KeyStore$Builder$FileBuilder$1"
   "java.net.URLClassLoader$3$1

点评

如果问题已经解决,请将分类改为“已解决”,谢谢  发表于 2013-3-25 07:04
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马