package com.xiaomo.reflex;

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 fin = new FileInputStream(file);


){


//一次读取Class文件的全部二进制数据


int r = fin.read(raw);


if(r != len){


throw new IOException("无法读取全部文件:"+r+" != "+len);


}

return raw;


}


}

private 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) {


System.out.println(e);


}


//获取javac线程的退出值


int ret = p.exitValue();


return ret == 0;


}

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{


//如果编译失败,或者改class文件不存在


if(!compile(javaFilename)||!classFile.exists()){


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();


}


}


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 cc1 = new CompileClassLoader();


//加载需要运行的类


Class<?> clazz = cc1.loadClass(progClass);


//获取需要运行的类的主要方法


Method main = clazz.getMethod("main",(new String[0]).getClass());


Object argsArray[] = {progArgs};


main.invoke(null, argsArray);


}

}

java 自制类加载器的简单实现的更多相关文章

  1. Java自定义类加载器与双亲委派模型

    其实,双亲委派模型并不复杂.自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用.但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行.可是自定义类 ...

  2. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  3. 深入探讨java的类加载器

    类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Ja ...

  4. java自定义类加载器

    前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...

  5. java 中类加载器

    jar 运行过程和类加载机制有关,而类加载机制又和我们自定义的类加载器有关,现在我们先来了解一下双亲委派模式. java 中类加载器分为三个: BootstrapClassLoader 负责加载 ${ ...

  6. Java 基础 类加载器和双亲委派机制 学习笔记

    转自博客:https://blog.csdn.net/weixin_38118016/article/details/79579657 文章不是我写的,但是感觉写的挺通俗易懂的,然后防止以后丢失,就转 ...

  7. Java 虚拟机类加载器

    虚拟机设计团队把类加载阶段张的”通过一个类的全限定名来获取此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为”类加载器”. ...

  8. java ClassLoader类加载器

    原文 首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java ...

  9. java高新技术-类加载器

    1.类加载器及委托机制的深入分析 > 类加载器的作用:一个java文件中的出现的类,首先要把这个类的字节码加载到内存中,这个类的信息放在硬盘的classPath下的class文件中,  把cla ...

随机推荐

  1. 【iOS知识学习】_iOS沙盒机制

    IOS中的沙盒机制(SandBox)是一种安全体系,它规定了应用程序仅仅能在为该应用创建的目录内读取文件,不能够訪问其它地方的内容.全部的非代码文件都保存在这个地方.比方图片.声音.属性列表和文本文件 ...

  2. MySQL(14):Select-limit(限制获得的记录数量)

    1. limit 限制获得记录的数量 2.limit 语法: (1) limit  offset, row_count: offset偏移量,从0开始. row_count总记录数. 分析: 案例演示 ...

  3. unable to convert MySQL date/time value to System.DateTime

    今天 用C# MySql做项目的时候 遇到了 unable to convert MySQL date/time value to System.DateTime 这样的异常错误,这个原因是因为:表里 ...

  4. Android触摸事件的分发机制

    ---恢复内容开始--- 一.MotionEvent : ACTION_DOWN(下按事件).ACTION_UP(松开事件).ACTION_MOVE(移动事件) 二.三大函数 1.dispatchTo ...

  5. SelectObject

    CPen* SelectObject( CPen* pPen ); CBrush* SelectObject( CBrush* pBrush ); virtual CFont* SelectObjec ...

  6. js插件zClip实现复制到剪贴板功能

    相信这个功能大家平时上网经常能碰到,以前也没怎么留意怎么实现的,直到项目中需要. 网上一搜一大堆,单纯使用js方法也不是没有,但是由于各浏览器的安全机制不同,不是跨浏览器的.去看了几个常用的网站,都是 ...

  7. Thinkphp 数据的修改及删除操作

    一.数据修改操作 save()  实现数据修改,返回受影响的记录条数 具体有两种方式实现数据修改,与添加类似(数组.AR方式) 1.数组方式: a)         $goods = D(“Goods ...

  8. gcc使用笔记

    1.如何在gcc中传输宏定义? 参考如下红色部分,可以传入宏定义 gcc [-c|-S|-E] [-std=standard] [-g] [-pg] [-Olevel] [-Wwarn...] [-p ...

  9. java获取当前时间

    /////////////////获取时间方法一////////////////////////////// java.util.Date uDate=new java.util.Date(); Sy ...

  10. C# 文件创建时间,修改时间

    System.IO.FileInfo fi = new System.IO.FileInfo(@"D:\site\EKECMS\skin\Grey\default#.html"); ...