1.反射
程式執行時,允許程式結構或者變數的型別,這種語言成為動態語言,如Python,Puby是動態語言,顯然java不是動態語言,但是java有一個非常突出的動態相關機制:Reflection--反射.
反射定義:java反射機制是在執行狀態中,對於任意一個類,都能知道這個類的所有屬性和方法,對於任意一個物件,都能夠呼叫它的任意一個方法和屬性,這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制
一般情況下,我們在使用一個類時,是先獲得一個類,然後例項化這個類,但是通過反射我們可以通過一個物件獲取到類中的資訊.
java的反射機制可以實現的功能:
1.在執行時判斷任意一個物件所屬的類;
2.在執行時構造任意一個類的物件;
3.在執行時判斷任意一個類所具備的成員變數和方法;
4.在執行時呼叫任意一個物件的方法
5.生成動態代理
2.獲取Class
使用反射機制最先應該獲取Class物件.Class物件就是反射的源頭.java中的反射機制.
當一個類被載入後.java虛擬機器就會自動產生一個Class物件,一個類只會生成一個Class物件.在Class物件中存在著這個類中的所有內容,比如成員屬性,成員方法,構造方法
1.獲取Class物件的方法
1.物件.getClass()
2.類名.class
3.Class.forname("包名+類名")
例子1:
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
// 1.類名.class
Class<String> cls1 = String.class;
System.out.println(cls1);
// 2.物件.getClass()
Class<? extends String> cls2 = "哈哈".getClass();
System.out.println(cls2);
// 3.Class.forName("包名+類名")
Class<?> cls3 = Class.forName("java.lang.Object");
System.out.println(cls3);
// 根據包裝型別.TYPE屬性獲取對應基本資料型別的Class物件
Class<Integer> cls7 = Integer.TYPE;
System.out.println(cls7);
Class cls5 = int.class;
System.out.println(cls5);
}
}
複製程式碼
三種使用方式主要使用第三種,第一種我們已經有了物件,所以用反射的意義不大.第二種需要導包,不導包編譯就不通過,依賴性太強.所以我們主要使用第三種,我們可以直接傳入字串也可以把字串寫在配置檔案中.
3.通過反射獲取構造方法
我們先定義一個Person類:
public class Person {
private String name;
private int age;
private String id;
public Person() {
System.out.println("我是空參構造");
}
private Person(String id) {
this.id = id;
System.out.println("我是私有單參構造");
}
public Person(String name, int age, String id) {
this.name = name;
this.age = age;
this.id = id;
System.out.println("我是公共三參構造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "[name=" + name + ", age=" + age + ", id=" + id + "]";
}
}
複製程式碼
1.獲取構造方法
通過反射可以獲取一個類的構造方法
例子2:
public class Simple {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 獲得Person類的Class物件
Class<Person> cla = Person.class;
// 獲得Person類中的構造方法,利用getConstructors()方法可以獲得此類公共構造方法的 Constructor 物件陣列
Constructor<Person>[] con = (Constructor<Person>[]) cla.getConstructors();
System.out.println(Arrays.toString(con));
// 利用getConstructor()方法可以獲得指定的公共構造方法,可根據傳入的引數返回相應的構造方法
Constructor<Person> con1 = cla.getConstructor(String.class, int.class, String.class);
System.out.println(con1);
// 利用getDeclaredConstructors()方法可以獲得此類所有已宣告的構造方法的 Constructor 物件的陣列
Constructor<Person>[] con2 = (Constructor<Person>[]) cla.getDeclaredConstructors();
System.out.println(Arrays.toString(con2));
// 利用getDeclaredConstructor()方法可以返回一個 Constructor 物件,該物件反映此 Class
// 物件所表示的類或介面的指定構造方法
Constructor<Person> con3 = cla.getDeclaredConstructor(String.class);
System.out.println(con3);
}
}
複製程式碼
程式執行結果:
[public com.shy.test.Person(java.lang.String,int,java.lang.String), public com.shy.test.Person()]
public com.shy.test.Person(java.lang.String,int,java.lang.String)
[public com.shy.test.Person(java.lang.String,int,java.lang.String), private com.shy.test.Person(java.lang.String), public com.shy.test.Person()]
private com.shy.test.Person(java.lang.String)
複製程式碼
4.通過反射獲取成員變數使用
1.批量的
Field[] getFields():獲取所有的"公有欄位"
複製程式碼
Field[] getDeclaredFields():獲取所有欄位,包括:私有.受保護.預設.公有
複製程式碼
2.獲取單個的
public Field getField(String fieldName):獲取某個"公有的"欄位
複製程式碼
public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
複製程式碼
例子4:
import java.lang.reflect.Field;
public class Simple {
public static void main(String[] args) throws Exception {
// 獲得Person類的Class物件
Class<Person> cla = Person.class;
//獲取欄位
System.out.println("---------------獲取所有的屬性(包括私有、受保護、預設的)-------------");
Field[]fields=cla.getDeclaredFields();
for(Field f:fields){
System.out.println(f);
}
System.out.println("-----------------獲得屬性並呼叫--------------------------");
//獲取屬性並呼叫
Field f=cla.getDeclaredField("name");
System.out.println(f);
//獲取一個物件
Person p=cla.getConstructor().newInstance();
//放開許可權
f.setAccessible(true);
/* 通過set(Object obj,Object value)方法設定屬性值
* obj:要設定的欄位所在的物件
* value:要為欄位設定的值
*/
f.set(p,"zhangsan");
System.out.println(p);
}
}
複製程式碼
程式執行結果:
---------------獲取所有的屬性(包括私有、受保護、預設的)-------------
private java.lang.String com.shy.test.Person.name
private int com.shy.test.Person.age
private java.lang.String com.shy.test.Person.id
-----------------獲得屬性並呼叫--------------------------
private java.lang.String com.shy.test.Person.name
我是空參構造
[name=zhangsan, age=0, id=null]
複製程式碼