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); } }
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小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。