Java進階之reflection(反射機制)——反射概念與基礎
反射機制是Java動態性之一,而說到動態性首先得了解動態語言。那麼何為動態語言?
一、動態語言
動態語言,是指程式在執行時可以改變其結構:新的函式可以引進,已有的函式可以被刪除等結構上的變化。比如常見的JavaScript就是動態語言,除此之外Ruby,Python等也屬於動態語言,而C、C++則不屬於動態語言。
二、Java是動態語言嗎?
從動態語言能在執行時改變程式結構結構或則變數型別上看,Java和C、C++一樣都不屬於動態語言。
但是JAVA卻又一個非常突出的與動態相關的機制:反射機制。Java通過反射機制,可以在程式執行時載入,探知和使用編譯期間完全未知的類,並且可以生成相關類物件例項,從而可以呼叫其方法或則改變某個屬性值。所以JAVA也可以算得上是一個半動態的語言
三、反射機制:
1.反射機制概念
在Java中的反射機制是指在執行狀態中,對於任意一個類都能夠知道這個類所有的屬性和方法;並且對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取資訊以及動態呼叫物件方法的功能成為Java語言的反射機制。
2.反射的應用場合
在Java程式中許多物件在執行是都會出現兩種型別:編譯時型別和執行時型別。
編譯時的型別由宣告物件時實用的型別來決定,執行時的型別由實際賦值給物件的型別決定
如:
Person p=new Student();
其中編譯時型別為Person,執行時型別為Student。
除此之外,程式在執行時還可能接收到外部傳入的物件,該物件的編譯時型別為Object,但是程式有需要呼叫該物件的執行時型別的方法。為了解決這些問題,程式需要在執行時發現物件和類的真實資訊。然而,如果編譯時根本無法預知該物件和類屬於哪些類,程式只能依靠執行時資訊來發現該物件和類的真實資訊,此時就必須使用到反射了。
四、Java反射API
反射API用來生成JVM中的類、介面或則物件的資訊。
- Class類:反射的核心類,可以獲取類的屬性,方法等資訊。
- Field類:Java.lang.reflec包中的類,表示類的成員變數,可以用來獲取和設定類之中的屬性值。
- Method類: Java.lang.reflec包中的類,表示類的方法,它可以用來獲取類中的方法資訊或者執行方法。
- Constructor類: Java.lang.reflec包中的類,表示類的構造方法。
五、使用反射的步驟
1.步驟
- 獲取想要操作的類的Class物件
- 呼叫Class類中的方法
- 使用反射API來操作這些資訊
2.獲取Class物件的方法
- 呼叫某個物件的getClass()方法
Person p=new Person();
Class clazz=p.getClass();
- 呼叫某個類的class屬性來獲取該類對應的Class物件
Class clazz=Person.class;
- 使用Class類中的forName()靜態方法; (最安全/效能最好)
Class clazz=Class.forName("類的全路徑"); (最常用)
3.獲取方法和屬性資訊
當我們獲得了想要操作的類的Class物件後,可以通過Class類中的方法獲取並檢視該類中的方法和屬性。
示例程式碼:
<<<<<<<<<<<<<<<<<<<<<<Person類<<<<<<<<<<<<<<<<<<<<<<<<<<
package reflection;
public class Person {
private String name;
private String gender;
private int age;
public Person() {
}
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
//getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return "姓名:"+name+" 性別:"+gender+" 年齡:"+age;
}
}
<<<<<<<<<<<<<<<<使用反射<<<<<<<<<<<<<<<<<<<
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
* 通過使用者輸入類的全路徑,來獲取該類的成員方法和屬性
* Declared獲取全部不管是私有和公有
* 1.獲取訪問類的Class物件
* 2.呼叫Class物件的方法返回訪問類的方法和屬性資訊
*/
public class Test {
public static void main(String[] args) {
try {
//獲取Person類的Class物件
Class clazz=Class.forName("reflection.Person");
//獲取Person類的所有方法資訊
Method[] method=clazz.getDeclaredMethods();
for(Method m:method){
System.out.println(m.toString());
}
//獲取Person類的所有成員屬性資訊
Field[] field=clazz.getDeclaredFields();
for(Field f:field){
System.out.println(f.toString());
}
//獲取Person類的所有構造方法資訊
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){
System.out.println(c.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出結果:
方法資訊:
public java.lang.String reflection.Person.toString()
private java.lang.String reflection.Person.getName()
private void reflection.Person.setName(java.lang.String)
public void reflection.Person.setAge(int)
public int reflection.Person.getAge()
public java.lang.String reflection.Person.getGender()
public void reflection.Person.setGender(java.lang.String)
屬性資訊:
private java.lang.String reflection.Person.name
private java.lang.String reflection.Person.gender
private int reflection.Person.age
構造方法資訊
private reflection.Person()
public reflection.Person(java.lang.String,java.lang.String,int)
4.建立物件
當我們獲取到所需類的Class物件後,可以用它來建立物件,建立物件的方法有兩種:
- 使用Class物件的newInstance()方法來建立該Class物件對應類的例項,但是這種方法要求該Class物件對應的類有預設的空構造器。
- 先使用Class物件獲取指定的Constructor物件,再呼叫Constructor物件的newInstance()方法來建立 Class物件對應類的例項,通過這種方法可以選定構造方法建立例項。
示例程式碼:
package reflection;
import java.lang.reflect.Constructor;
public class Demo01 {
public static void main(String[] args) {
try {
//獲取Person類的Class物件
Class clazz=Class.forName("reflection.Person");
/**
* 第一種方法建立物件
*/
//建立物件
Person p=(Person) clazz.newInstance();
//設定屬性
p.setName("張三");
p.setAge(16);
p.setGender("男");
System.out.println(p.toString());
/**
* 第二種方法建立
*/
//獲取構造方法
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//建立物件並設定屬性
Person p1=(Person) c.newInstance("李四","男",20);
System.out.println(p1.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
輸出結果:
姓名:張三 性別:男 年齡: 16
姓名:李四 性別:男 年齡: 20
好了,以上是Java反射機制的簡單介紹,下一篇文章我將講一下反射的兩個具體應用,通過反射操作註解和通過反射操作泛型,有興趣的同學可以瞭解一波。