Java的语言特点是什么(java语言的主要特点是什么)
576
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
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小时内删除侵权内容。