一、簡介:
java不算是動態語言,但是卻含有一些動態性機制功能。體現java動態性的有:反射機制、動態編譯、動態執行javascript代碼和動態字節碼操作等。在這裏介紹一下java動態性中的反射機制。反射機制是在java程序運行狀態中,可以動態的記載類,對於已經加載的類,可以知道這個類的所有屬性和方法,也可以操作其對象的相關屬性和方法。加載類之後會在堆內存中生成該類的一個Class類型的對象,該對象中包含該類的結構信息,結構信息和類的相關信息形成一種映射關係,這就體現了類本身和Class對象的反射關係。
二、操作:
1、Class類型對象的獲取:
獲取Class類型對象有三種方法,如下語句:
<pre class="java" name="code"> Class clazz = Class.forName(path);
Class strClazz = String.class;
Class strClazz2 = path.getClass();
其中常用的還是Class.forName(對象名)這個方法。
2、利用反射API獲取和操作類的相關信息。
其核心代碼如下:
Class<User> clazz = (Class<User>) Class.forName(path);
//通過反射API調用構造方法,構造對象
//1、調用User無參構造方法生成新對象
User u = clazz.newInstance();
//2、調用User指定參數的構造方法生成新對象。
Constructor<User> c =
clazz.getDeclaredConstructor(int.class,int.class,String.class);
User u2 = c.newInstance(1001,18,"高淇二");
//通過反射API調用普通方法
User u3 = clazz.newInstance();
Method method = clazz.getDeclaredMethod("setUname", String.class);
method.invoke(u3, "高淇三"); //相當於u3.setUname("高淇三");
//通過反射API操作屬性
User u4 = clazz.newInstance();
Field f = clazz.getDeclaredField("uname");
f.setAccessible(true); //指定屬性不需要做安全檢查了,可以直接訪問
f.set(u4, "高淇四"); //通過反射直接寫屬性
下邊說明有關setAccessible方法,一般情況下反射只可以訪問類中的非靜態成員,如果要訪問類中的靜態成員,需要通過setAccessible方法設置該屬性可以直接訪問不需要做安全檢查;反射的一大缺點就是需要速度慢,主要就是在於每次訪問都需要做安全檢查,因此如果需要避免反射速度慢的缺點,必要時候也會犧牲安全因素,提高運行速度,這時就需要通過setAccessible方法進行設置。
3、通過反射獲取泛型:
核心代碼如下:
//獲得指定方法參數泛型信息
Method m = Demo04.class.getMethod("test01", Map.class,List.class);
Type[] t = m.getGenericParameterTypes();
for (Type paramType : t) {
System.out.println("#"+paramType);
if(paramType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("泛型類型:"+genericType);
}
}
}
//獲得指定方法返回值泛型信息
Method m2 = Demo04.class.getMethod("test02", null);
Type returnType = m2.getGenericReturnType();
if(returnType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型類型:"+genericType);
}
}
4、反射操作註解:
有關操作註解:這裏定義了兩個自定義的註解和一個操作類,SxtTable、SxtField以及Demo類,用於模擬代碼信息生成數據庫對應表信息的過程,其相關代碼如下:
自定義註解SxtTable:
@Target(value={ElementType.TYPE}) //修飾範圍爲類或接口等。
@Retention(RetentionPolicy.RUNTIME) //定義註解的生命週期。
public @interface SxtTable {
String value();
}
自定義註解SxtField:
@Target(value={ElementType.FIELD}) //修飾範圍爲類型成員。
@Retention(RetentionPolicy.RUNTIME) //定義註解的生命週期。
public @interface SxtField {
String columnName();
String type();
int length();
}
操作類:
@SxtTable("tb_student")
public class SxtStudent {
@SxtField(columnName="id",type="int",length=10)
private int id;
@SxtField(columnName="sname",type="varchar",length=10)
private String studentName;
@SxtField(columnName="age",type="int",length=3)
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
三、總結:
通過反射初步認識了有關java動態性的一些操作,但是有關反射的運用遠遠不止這些,反射是java中非常有力的一個功能,當然反射也有自己的一些缺陷,在運用中需要權衡好其利弊,儘量做到將其利益最大化。