標籤:
反射機制的原理
??
一般來說,如果想產生一個類的對象,那麼運行這個程式的JVM會去確認這個類的class對象是否已經載入。如果尚未載入,那麼JVM會根據類名尋找.class檔案,並將其載入,一旦這個類的class對象被載入記憶體,它就可以被用來建立這個類的的所有對象
??
另外如果遇到一個未知類型的引用,(JVM?)通常會採用強制類型轉換的形式來得到開發人員想要的類型引用,如果執行了錯誤的類型轉換,則會報一個ClassCastException異常
??
在以上兩個過程中,Class類一直都在起作用,因為Class類執行個體包含的是一個類的全部資訊,包括方法、屬性、構造器等
??
如果不是在啟動時去建立這個Class執行個體,而是在運行時獲得這個Class類執行個體,那麼我們就可以動態去載入一個類,動態調用類的方法,已經動態去訪問一個類的屬性,反射機制就是為這種情境而產生的,反射機制的出發點就在於JVM會為每個類建立一個java.lang.Class類的執行個體,通過該對象可以擷取該類的全部資訊,然後通過java.lang.reflect包下的API以達到以上所述的動態需求
??
三種情況會導致一個Java類被載入到JVM中
??
Student stu=new Student();
使用該類建立對象
??
System.out.println(student.count)
訪問該類的靜態成員
??
Class.forName("com.Student");
使用Class類的靜態方法forName方法,動態載入一個指定類名的類
ps…JDBC匯入驅動類就是一個很常用的例子
??
三種得到一個類Class對象的方法
??
Class類forName方法返回的就是一個類的對象的引用
??
通過類的Class屬性
Class<Student> clazz=Student.class;
??
通過getClass方法,這個方法是從Object類繼承下來的
Student stu=new Student();
Class<Student> clazz=stu.getClass();
??
ps…獲得類的Class對象後,就可以用這個對象建立和調用和訪問這個類中的各種東西了
ps…Class類對象的方法getName、getConstructor、getMethod、newInstance
??
Field的用法:操作類的成員變數
??
通過Class類的getDeclaredField方法可以獲得一個Field類對象的引用,有了這個對象的引用之後,就可以調用該對象的getXXX方法,其中XXX包括int,double,byte等獲得某個成員變數
??
通過Field對象的使用來按照某一規則比較兩個對象的大小
??
private static FieldReflect compareReflect(FieldReflect obj1,FieldReflect obj2)
??
三種獲得的方式,本質上是三種獲得Class對象的方式
??
//1
Field field=obj1.getClass().getDeclaredField("age");
//2
Field field=FieldReflect.class.getDeclaredField("age");
//3
Class clazz = Class.forName("com.FieldReflect.FieldReflect");
??
得到Class對象之後,就可以調用getDeclaredField方法得到Field對象的引用了
??
Field field = clazz.getDeclaredField("age");
??
得到Field對象的引用之後,就可以調用getXXX方法獲得某一成員變數了
??
Field的用法:操作類的私人成員
??
首先我們寫一個類,類的成員變數為私人
??
class PrivateFieldReflectClass {
private String name;
private int age;
public PrivateFieldReflectClass(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
然後我們在主類中去通過反射機製得到類的Field類
??
public class PrivateFieldReflectTest {
public static void main(String[] args) {
PrivateFieldReflectClass fieldReflect1 = new PrivateFieldReflectClass(
"Tong", 23);
// 訪問私人變數
Class<PrivateFieldReflectClass> clazz = PrivateFieldReflectClass.class;
Field field = clazz.getDeclaredField("age");
// field.setAccessible(true);
System.out.println(field.getInt(fieldReflect1));
}
}
??
當我們試圖去訪問私人變數時,會發生錯誤java.lang.IllegalAccessException
如果我們想去訪問私人變數,需要把Field的執行個體對象設定Accessible屬性為true即可
??
Field的用法:覆蓋toString方法,使其能夠動態更改類對象的toString展示
??
需要覆蓋類中的toString方法,主要思想就是用類對象的getDeclaredFields方法得到Field數組,迴圈遍曆,得到相應的Name和Value
??
class DataObject{
private String name;
private int age;
private String description;
private String other;
public DataObject(String name, int age, String description, String other) {
super();
this.name = name;
this.age = age;
this.description = description;
this.other = other;
}
@Override
public String toString() {
StringBuffer sb=new StringBuffer();
Field[] fields=DataObject.class.getDeclaredFields();
for (Field field : fields) {
sb.append(field.getName());
sb.append("=");
sb.append(field.get(this));
sb.append("\n");
}
return sb.toString();
}
}
??
Method的用法:操作類的方法
??
Method類,代表的是類的方法,包括靜態和非靜態,與Field類似,通過反射機制,具體來說就是通過Class類對象的getMethod方法可以獲得Method類的對象,然後通過該對象額invoke方法,將類名作為參數傳入該方法,即可完成方法的調用
??
首先類中定義兩個方法
??
public class MethodReflect {
public void m1() {
System.out.println("method 1");
}
public void m2() {
System.out.println("method 2");
}
}
??
然後在main函數就可以利用反射機制擷取並調用想要的方法了
反射機制的過程仍舊是先得到類的對象的引用,然後通過類對象的getDeclaredMethod方法得到方法類對象的引用,然後建立一個類的對象,然後利用方法對象的invoke方法將剛建立的類對象作為參數傳入,注意,這裡如果方法有參數,需要將參數列表也作為參數傳入invoke中
??
Class clazz=MethodReflect.class;
Method method=clazz.getDeclaredMethod("m1");
MethodReflect methodReflect=new MethodReflect();
method.invoke(methodReflect);
??
Constructor類的用法:利用反射機制執行個體化一個類
??
一般來說,我們可以通過new關鍵字執行個體化一個類,也就是建立一個類的對象,而如何通過反射機制執行個體話一個類呢,其實不管是通過new關鍵字還是通過反射,都是去調用類的建構函式,如果是去調用無參的建構函式,我們可以使用Class的newInstance方法。如果是要用到有參的建構函式的話,我們就需要用到反射包下的Constructor類
??
首先也是要得到類的對象的引用
??
Class<Student> clazz1=Student.class;
//無參:通過newInstance
Student student1=clazz1.newInstance();
//有參:通過構造器
Constructor<Student> constructor=clazz1.getConstructor(String.class,int.class);
student1=constructor.newInstance("Tong",23);
??
基礎知識:Java反射機制