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

举报
谙忆 发表于 2021/05/28 08:10:43 2021/05/28
【摘要】 做自己的类加载器 虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行。那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能。 以下内容摘自API文档: 应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。 网络类加载器子类必须定义方法 findClass 和 ...

做自己的类加载器

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


}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

测试结果:

看,最后那句不能输出吧。
因为不是一个类加载器的。

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

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

测试类: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..."); }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

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; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

运行测试结果:

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

再看运行结果:

这个可以有很多改进的地方,就比如每次输入路径都很麻烦,
我们可以做一个图形界面,让我们自己选择。
这样就方便多了。

文章来源: chenhx.blog.csdn.net,作者:谙忆,版权归原作者所有,如需转载,请联系作者。

原文链接:chenhx.blog.csdn.net/article/details/51332746

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。