Java 反射是Java語言的一個很重要的特征。它允許運行中的 Java 程序對自身進行檢查,并能直接操作程序的內部屬性。例如,使用它能獲得Java 類中各成員的名稱并顯示出來。
Java 反射機制主要提供了以下功能:
a.在運行時判斷任意一個對象所屬的類。
b.在運行時構造任意一個類的對象。
c.在運行時判斷任意一個類所具有的成員變量和方法。
d.在運行時調用任意一個對象的方法。
在JDK中,主要由以下類來實現Java反射機制,這些類在java.lang.reflect包中:
Class類:代表一個類。
Field 類:代表類的成員變量(成員變量也稱為類的屬性)。
Method類:代表類的方法。
Constructor 類:代表類的構造方法。
Array類:提供了動態創建數組,以及訪問數組的元素的靜態方法。
下面寫了一個程序:設計了一個POJO類。所謂POJO類,本人粗淺的理解即和JavaBean類似,只有字段和setter/getter方法。然后在主函數通過反射,在控制臺打印該POJO類的所有字段和方法。
本人設計的POJO類為WorkerPOJO.java,然后另一個測試類為POJOReflection.java,在main函數中負責打印該類的所有字段和方法。程序見下:
WorkerPOJO.java:
1
package com.xpec.landon.trainjava.annotation;
2
/** *//**
3
* POJO類,和JavaBean相似
4
* @author landon
5
*
6
*/
7
public class WorkerPOJO
{
8
private String name;
9
private int age;
10
11
/** *//**
12
* 用Annotation修飾
13
* @return 姓名
14
*/
15
@WorkerPOJOAnnotation(name = "landon",age = 22)
16
public String getName()
{
17
return name;
18
}
19
public void setName(String name)
{
20
this.name = name;
21
}
22
public int getAge()
{
23
return age;
24
}
25
public void setAge(int age)
{
26
this.age = age;
27
}
28
29
}
30
31
POJOReflection.java:
1
package com.xpec.landon.trainjava.annotation;
2
import java.lang.reflect.Field;
3
import java.lang.reflect.Modifier;
4
import java.lang.reflect.Method;
5
6
7
/** *//**
8
* 運用Java的反射機制,輸出POJO類的字段和方法(新增了Annotation的修飾)
9
* @author landon
10
*
11
*/
12
public class POJOReflectionTest
{
13
public static void main(String[] args)
14
{
15
try
16
{
17
//加載WorkPOJO,注意這里一定要寫全類名,包括包名,因為包名是類名的一部分
18
Class pojo = Class.forName("com.xpec.landon.trainjava.annotation.WorkerPOJO");
19
//獲取域的數組
20
Field []fieldList = pojo.getDeclaredFields();
21
//獲取方法的數組
22
Method []methodList = pojo.getDeclaredMethods();
23
24
System.out.println("WorkerPOJO類的所有字段:");
25
System.out.println("修飾符" + " " + "類型" + " " + "字段名");
26
27
for(int i = 0;i < fieldList.length;i++)
28
{
29
Field field = fieldList[i];
30
//用下面的形式獲取具體的修飾符
31
System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getType() + " " + field.getName());
32
}
33
34
System.out.println();
35
System.out.println("WorkerPOJO類的所有方法(不包括annotation修飾的方法):");
36
37
for(int j = 0;j < methodList.length;j++)
38
{
39
Method method = methodList[j];
40
//判斷方法是否被Annotation修飾
41
boolean methodAnnotation = method.isAnnotationPresent(WorkerPOJOAnnotation.class);
42
43
//如果被annotation修飾,則過濾掉該方法,即不輸出
44
if(methodAnnotation)
45
{
46
continue;
47
}
48
//獲取方法參數列表
49
Class parameters[] = method.getParameterTypes();
50
51
System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " + method.getName() + " (");
52
53
for(int k = 0;k < parameters.length;k++)
54
{
55
System.out.print(parameters[k].toString());
56
}
57
58
System.out.println(")");
59
}
60
}
61
catch(ClassNotFoundException exception1)
62
{
63
exception1.printStackTrace();
64
}
65
66
}
67
68
}
69
70
下面是程序的一個運行截圖:

可以看到,在WorkerPOJO類中引入了Annotation。下面,我們詳細介紹一下Annotation:
在使用JUnit4中,我們可以看到在每個測試方法前面都有一個@Test標記,這就是傳說中的Annotation。
Annotation 提供了一條與程序元素關聯任何信息或者任何元數據(metadata)的途徑。從某些方面看,annotation就像修飾符一樣被使用,并應用于包、類型、構造方法、方法、成員變量、參數、本地變量的聲明中。這些信息被存儲在annotation的“name=value”結構對中。 annotation類型是一種接口,能夠通過java反射API的方式提供對其信息的訪問。
annotation能被用來為某個程序元素(類、方法、成員變量等)關聯任何的信息。需要注意的是,這里存在著一個基本的潛規則:annotaion不能影響程序代碼的執行,無論增加、刪除 annotation,代碼都始終如一的執行。另外,盡管一些annotation通過java的反射api方法在運行時被訪問,而java語言解釋器在工作時忽略了這些annotation。正是由于java虛擬機忽略了annotation,導致了annotation類型在代碼中是“不起作用”的;只有通過某種配套的工具才會對annotation類型中的信息進行訪問和處理。
annotation是與一個程序元素相關聯信息或者元數據的標注。它從不影響
ava程序的執行,但是對例如編譯器警告或者像文檔生成器等輔助工具產生影響。
我的理解是:Annotation是繼承自java.lang.annotation.Annotation的類,用于向程序分析工具或虛擬機提供package class field methed 等方面的信息,它和其他類沒什么區別,除了使用方式。
下面寫了一個簡單的Annotation:WorkerPOJOAnnotation.java
1
package com.xpec.landon.trainjava.annotation;
2
import java.lang.annotation.Documented;
3
import java.lang.annotation.ElementType;
4
import java.lang.annotation.Retention;
5
import java.lang.annotation.RetentionPolicy;
6
import java.lang.annotation.Target;
7
8
/** *//**
9
* 修飾WorkerPOJO類方法的一個Annotation
10
* @author landon
11
*
12
*/
13
14
@Target(ElementType.METHOD)
15
@Retention(RetentionPolicy.RUNTIME)
16
@Documented
17
public @interface WorkerPOJOAnnotation
{
18
String name();
19
int age();
20
21
}
22
23
其中@Target里面的ElementType是用來指定Annotation類型可以用在哪一些元素上的,包括TYPE(類型),METHOD(方法),FIELD(字段),PARAMETER(參數)等。其中TYPE是指可以用在Class,Interface等類型上。下面給出用jad反編譯出的ElementType中的靜態變量的截圖:

另外@Retention中的RetentionPolicy是指Annotation中的信息保留方式,分別是SOURCE,CLASS 和 RUNTIME. SOURCE代表的是這個Annotation類型的信息只會保留在程序源碼里,源碼如果經過了編譯之后,Annotation的數據就會消失,并不會保留在編譯好的.class文件里面。 ClASS的意思是這個Annotation類型的信息保留在程序源碼里,同時也會保留在編譯好的.class文件里面,在執行的時候,并不會把這一些信息加載到虛擬機(JVM)中去.注意一下,當你沒有設定一個Annotation類型的Retention值時,系統默認值是CLASS. 第三個,是RUNTIME,表示在源碼、編譯好的.class文件中保留信息,在執行的時候會把這一些信息加載到JVM中去的.
下面給出用jad反編譯出的RetentionPolicy中的靜態變量的截圖

最后的一個Annotation@Documented是指目的就是讓這一個Annotation類型的信息能夠顯示在Java API說明文檔上。
下面將上面自己設計的WorkerPOJOAnnotation應用在了WorkerPOJO類的一個方法前面:
然后在控制臺輸出了沒有被Annotation注釋的字段和方法,運行后可以看到不包括getName方法。
最后我們可以用Junit4書寫一個測試用例: POJOReflectionJunit4Test.java
1
package com.xpec.landon.trainjava.annotation;
2
import java.lang.reflect.Field;
3
import java.lang.reflect.Method;
4
5
import javax.activation.FileDataSource;
6
7
import junit.framework.Assert;
8
9
import org.junit.After;
10
import org.junit.Before;
11
import org.junit.Test;
12
13
/** *//**
14
* 關于Java反射以及Annotation的一個TestCase
15
* @author landon
16
*
17
*/
18
19
public class POJOReflectionJunit4Test
{
20
private Class pojo;
21
private Field []fieldList;
22
private Method[] methodList;
23
24
@Before
25
public void setUp() throws Exception
{
26
//加載類WorkPOJO
27
pojo = Class.forName("com.xpec.landon.trainjava.annotation.WorkerPOJO");
28
//獲取域的數組
29
fieldList = pojo.getDeclaredFields();
30
//獲取方法的數組
31
methodList = pojo.getDeclaredMethods();
32
}
33
34
//測試字段和方法的個數
35
@Test
36
public void testSize()
37
{
38
Assert.assertEquals(2, fieldList.length);
39
Assert.assertEquals(4, methodList.length);
40
}
41
42
//測試字段是否帶有annotations
43
@Test
44
public void isFieldAnnotation()
45
{
46
for(int i = 0;i < fieldList.length;i++)
47
{
48
Assert.assertEquals(false, fieldList[i].isAnnotationPresent(WorkerPOJOAnnotation.class));
49
}
50
}
51
52
//測試方法是否帶有annotations
53
@Test
54
public void isMethodAnnotation()
55
{
56
for(int i = 0;i < methodList.length;i++)
57
{
58
Assert.assertEquals(false, methodList[i].isAnnotationPresent(WorkerPOJOAnnotation.class));
59
}
60
}
61
62
@After
63
public void tearDown() throws Exception
{
64
}
65
66
}
67
posted on 2010-07-14 12:19
landon 閱讀(2681)
評論(0) 編輯 收藏 所屬分類:
Program