java类中加 test_Java---注解、类加载器-加强-实现运行任意目录下class中加了@MyTest的空参方法...

做自己的类加载器

虚拟机的核心是通过类加载器来加载.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);

}

}

测试结果:

dc8d1e1f74abd40f45783dfea1eeaa4c.png

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

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

作自己的测试工具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);

}

}

}

}

运行测试结果:

a0fb1a8baed777d061541cc0187c067d.png

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

f0b24d3c252a313897835d0f51d06293.png

再看运行结果:

fcfbde5ee0d10d2ce0417235f71410fa.png

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

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

这样就方便多了。

本文同步分享在 博客“谙忆”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值