做自己的类加载器

虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行。那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能。

以下内容摘自API文档:

应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。

网络类加载器子类必须定义方法 findClass 和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例。

代码示例:

自己的类加载器 MyClassLoader

package cn.hncu;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import org.junit.Test; public class MyClassLoader extends ClassLoader{
public Class<?> findClass(String name){
//name = "e:\\cn\\hncu\\Person.class"
Class c = null;
FileInputStream in;
byte[] b=null; //通过IO或网络把字节码数据读取到buf[]当中。进一步地,
//如果我们自己熟悉字节码的生成格式,那么也可自己用程序生成。
//本例,我们是把硬盘中的一个外部字节码文件的数据读取到buf[]当中
//1
try {
in = new FileInputStream(name);
byte[] buf = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();//字节流
int len=0;
while((len=in.read(buf))!=-1){
baos.write(buf, 0, len);
}
in.close();
baos.close();
b = baos.toByteArray();
//2 ---1-2这里可以抽取出来写一个loadClassData方法
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
c = defineClass("cn.hncu.Person", b, 0, b.length);
return c;
} @Test
public void testClassData() throws ReflectiveOperationException{
String className="cn.hncu.Person";
//用Java的类加载器加载一个
Class c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
System.out.println((Person)obj); System.out.println("-------------------");
className = "e:\\cn\\hncu\\Person.class";
Class c2 = findClass(className);
Object obj2 = c2.newInstance();
System.out.println(obj2); System.out.println((Person)obj2);//这句是有问题的
//※不同类加载器加载的对象是无法强转---可以理解是不同的生存空间
//Person p2 = (Person) obj2;//会挂的。
//因为obj2的生存空间是MyClassLoader,而Person的生成空间是AppClassLoader
//System.out.println(p2); } }

测试结果:

看,最后那句不能输出吧。

因为不是一个类加载器的。

作自己的测试工具MyJUnit

(注解与反射共同使用的案例 )

相关说明:

1)JUnit用的是@Test注解,我们用@MyTest注解。

2)JUnit已经嵌入到MyEclipse当中,我们自己的MyJUnit只要能独立运行就可以(不嵌入),同时这样我们也不方便在MyJUnit中以参数方式接收到被测试类的类名与方法名,只能以键盘输入的方式接收。

3)JUnit能实现指定单个方法来调用执行,由于不能利用MyEclipse传参,因此我们在MyJUnit程序中遍历所有的方法并通过判断是否声明@MyTest注解来决定是否调用执行该方法。

下面实现了运行任意目录下的实现了@MyTest注解的方法:

需要输入绝对路径名和类的完整名字。

注解:@MyTest

package cn.hncu.myJunit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)//运行时也存在,必须要加这个
@Target (ElementType.METHOD)//限制注解只能加在方法上
public @interface MyTest { }

测试类:TestPerson

package cn.hncu.myJunit;
/**
* 测试用的
* @author 陈浩翔
*
* @version 1.0 2016-5-6
*/
public class TestPerson { public void run1(){
System.out.println("run1...");
} @MyTest
public void run2(){
System.out.println("run2...");
} public void run3(){
System.out.println("run3...");
} @MyTest
public void run4(){
System.out.println("run4...");
} public void run5(){
System.out.println("run5...");
} }

MyClassLoader类:自己写的类加载器

package cn.hncu.myJunit;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; /**
* 自己写的类加载器
* @author 陈浩翔
*
* @version 1.0 2016-5-6
*/
public class MyClassLoader extends ClassLoader{ //我把它分成2个方法写了。
public Class<?> findClass(String name, String className) {
try {
byte b[] = loadClassData(name);
Class c = defineClass(className, b, 0, b.length);
return c;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
} private static byte[] loadClassData(String name) throws IOException {
byte buf[] = new byte[1024];
FileInputStream in = new FileInputStream(name);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len=0;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
in.close();
out.close();
byte b[] = out.toByteArray();
return b;
}
}

main方法类:

package cn.hncu.myJunit;

import java.lang.reflect.Method;
import java.util.Scanner; import cn.hncu.myJunit.MyClassLoader; /**
* @author 陈浩翔
* @version 1.0 2016-5-6
*/
public class MyJunit { public static void main(String[] args) throws ReflectiveOperationException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入需要运行的类的绝对路径(路径中不能有空格,需要类的.class文件):");
String name = sc.next();
System.out.println("请输入类的名称(包含包名):");
String className = sc.next();
Class c = (new MyClassLoader()).findClass(name, className);
//获得那个类了。 //那个类必须要有空参构造方法
Object obj = c.newInstance(); //获得这个类所有声明的方法,包括私有的
Method ms[] = c.getDeclaredMethods();
for(Method m:ms){
if(m.isAnnotationPresent(MyTest.class)){
m.invoke(obj, null);
}
}
}
}

运行测试结果:

现在我把class文件移动到D盘了。

再看运行结果:

这个可以有很多改进的地方,就比如每次输入路径都很麻烦,

我们可以做一个图形界面,让我们自己选择。

这样就方便多了。

Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法的更多相关文章

  1. Java---实现运行任意目录下class中加了@MyTest的空参方法(实现图形界面)

    说明: 因为上个代码,总是要输入完整的绝对路径,比较麻烦,于是,就写了这个小程序,直接进入文件对话框选择需要运行的class文件. 只需要提前输入完整的类名. 注意:加的MyTest必须打个包,加上: ...

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

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

  3. Java 虚拟机类加载器

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

  4. java面向对象--类加载器及Class对象

    类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终 ...

  5. java ClassLoader类加载器

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

  6. Java之类加载器(Class Loader)

    JVM默认有三个类加载器: Bootstrap Loader Bootstrap Loader通常有C编写,贴近底层操作系统.是JVM启动后,第一个创建的类加载器. Extended Loader E ...

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

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

  8. java自定义类加载器

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

  9. Java的类加载器

    一.类加载器的概念 类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 ...

随机推荐

  1. ie67 设置最小宽度最小高度

    1.最小宽度 min-width:1003px; _width:expression((document.documentElement.clientWidth||document.body.clie ...

  2. HDOJ 2037简单的贪心算法

    代码: #include<iostream> using namespace std; int main() { int n,s,t1[100],t2[100],i,t,j; while( ...

  3. gzip命令

    http://www.cnblogs.com/peida/archive/2012/12/06/2804323.html 减 少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时, ...

  4. 为什么我们不喜欢用富UI控件

    我们对于理解一般意义的抽象关系并没有问题,但如第一部分使用Entity Framework 时说明的,事实恰好相反.我们还喜欢在交付应用程序时利用抽象关系,比如使用Azure等云服务.在这两种情况下, ...

  5. log4j 1.2配置(转载)

    转载自:http://www.blogjava.net/kit-soft/archive/2009/08/28/292977.html 第一步:加入log4j-1.2.8.jar到lib下. 第二步: ...

  6. [转载]ecshop 实现订单导出功能 指定订单导出 EXCEL 数据文件

    当下很多功能都觉得理所当然,但是实际作为2012年停更的ECSHOP来说,很多功能其实都是缺少的,好比今天的要说的功能 订单导出 这个功能对于现在的产品设计来说,应该属于一个比较常规的功能,但是ECS ...

  7. Sphinx 排序模式 SetSortMode

    可使用如下模式对搜索结果排序: SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面) SPH_SORT_ATTR_DESC 模式, 按属性降序排列 (属性值越大的越是 ...

  8. Mysql访问 for橙子小海

    package com.mvc.model.dao; import com.mvc.model.daoutil.DBConn; import com.mvc.model.entity.Blog; 这是 ...

  9. how to make choices about girls?

    yb ldge nvhl, yige hf csmn, hv bmig, hv zofj, hfyb uhjnxn;ldyige ybdm bfbfde, gjjt hf djip, djui hfk ...

  10. hdu不要62

    Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来, ...