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

网友投稿 541 2022-05-28

做自己的类加载器

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

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

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盘了。

再看运行结果:

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

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

这样就方便多了。

Java

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:崩溃一致性:你的程序真的正确保存了数据吗?
下一篇:【云市场精选单品】不想打工想回家养牛?那你必须知道养牛行业最火的黑科技
相关文章