思維導圖
一.體系介紹
Java反射的目的是在運行時獲得某個類的所有成員,然後使用.其原理是將一個類的成員進行抽象並通過Class對象獲得,然後使用.
在Java的反射jar包,即reflect包中,有三個功能性接口:
- Member:一個類中的組成成員的抽象.一個類中,主要有四種成員>>>修飾符,變量,構造方法,普通方法.
- AnnotatedElement:表示此成員元素可以被註解,此接口定義了獲得註解的方法.
- GenericDeclaration:表示這個成員可以配合泛型使用.
此外,由於Java中有一種不太像是OOP的對象,數組,此jar包中有Array對象用以表示數組.
二.具體使用
首先,Class對象是獲得各個成員對象的基礎,也是媒介.通過Class對象可以獲得public成員,指定成員或者所有成員.
舉例用的類:
//舉例用的類,有公共的,私有的,有參數的,無參數的方法,字段,構造方法
class Student{
public String name;
private int age;
public Student(){
}
private Student(String name,int age){
this.name = name;
this.age = age;
}
public void pubInfo(){
System.out.println("Studnet:" + name + ">>>" + age);
}
private void priInfo(String school){
System.out.println("Studnet:" + name + ">>>" + age + ">>>" + school);
}
}
Class對象有三種生成方法:
//測試獲得Class對象的方法
public void testBuildClass() throws Exception{
//通過實例對象獲得Class對象,因爲反射一般要生成對象,所以不常用
Student s1 = new Student();
Class clazz1 = s1.getClass();
//通過類字面常量獲得Class對象,因爲必須要導入引用,所以不太常用
Class clazz2 = Student.class;
//通過特殊方法獲得Class對象,這是最常用的,但必須寫全路徑的包名
Class clazz3 = Class.forName("reflectdemo.Student");
}
接下來說三種主要的成員對象:
2.1Constructor對象
Constructor對象是對構造方法的抽象,利用他可以在運行時創建對象.
//測試Constructor對象
public void testConstructor() throws Exception{
//獲得Class對象作爲獲取的媒介
Class clazz = Class.forName("reflectdemo.Student");
//以下方法對於Method,Field對象是通用的,後面介紹時不再重複敘述
//獲得單個指定的public Constructor無參構造器
Constructor c1 = clazz.getConstructor();
//獲得對象,必須向下轉型,newInstance()只會返回Object對象
Student s1 = (Student)c1.newInstance();
s1.pubInfo();
//獲得特定的private構造方法
// 注意,在這裏,方法申明裏用了int而不是Integer,這裏就只能用int.class,用Integer.class會報異常.
//反射獲取方法不支持自動裝箱機制
Constructor c2 = clazz.getDeclaredConstructor(String.class,int.class);
//私有的訪問權限必須先設置爲可訪問
c2.setAccessible(true);
Student s2 = (Student)c2.newInstance("XIAOHAO",21);
s2.pubInfo();
//獲得所有的構造器
clazz.getDeclaredConstructors();
//獲得所有的public 構造器
clazz.getConstructors();
}
2.2Method對象
Method對象是對方法的抽象,獲取方法同Contructor對象大同小異,使用上有些微差別
//測試Method對象
public void testMothod() throws Exception{
//獲得Class對象作爲獲取的媒介
Class clazz = Class.forName("reflectdemo.Student");
//獲取方法時同Constructor有一點差別,需要指定方法名
Method m1 = clazz.getDeclaredMethod("priInfo", String.class);
m1.setAccessible(true);
//輸入參數進行調用,注意,調用方法時必須有實例對象,不然會報錯
//靜態方法可以不用
m1.invoke(new Student(),"長春理工大學");
m1 = clazz.getDeclaredMethod("priStatic",String.class);
m1.setAccessible(true);
//也會報異常
//m1.invoke("xiaohao");
}
2.3Field對象
Field對象是字段(成員變量)的抽象,獲得的方法也差不多,使用則不同於方法,畢竟是字段嘛.
//測試Field對象
public void testField() throws Exception{
//獲得Class對象作爲獲取的媒介
Class clazz = Class.forName("reflectdemo.Student");
//獲取age字段的對象
Field f1 = clazz.getDeclaredField("age");
f1.setAccessible(true);
Student s1 = new Student();
//設置指定對象的字段的值
f1.set(s1,21);
s1.pubInfo();
s1.name = "xiaohao";
//獲取指定對象的字段的值
f1 = clazz.getDeclaredField("name");
System.out.println(f1.get(s1));
}
2.4Modifer對象
是不是覺得還缺了點什麼,訪問修飾符啊,Modefier就是訪問修飾符的抽象,獲取和使用都不同於其他三個成員
//測試Modifer對象
public void testModifier() throws Exception{
//獲得Class對象作爲獲取的媒介
Class clazz = Class.forName("reflectdemo.Student");
//獲取age字段的對象
Field f1 = clazz.getDeclaredField("age");
f1.setAccessible(true);
//Class,Field,Constructor,Method都有此方法,獲取表示Modifier對象特定數值.
int x = f1.getModifiers();
//使用Modifier對象進行解釋,toStirng(x)會輸出所有修飾符,可以使用Modifier.isPublic()等其他方法進行驗證.
System.out.println(Modifier.toString(x));
}
最後補充一點,有reflect包的體系可以看出三個主要的成員是實現了獲取泛型和註解的功能接口的,這篇文章裏就不多說了.使用大同小異.