JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態擷取的資訊以及動態調用對象的方法的功能稱為JAVA語言的反射機制。
1.取得Class類的對象的三種方法
取得Class對象:public final Class<?> getClass(),反射之中的所有泛型都定義為。,傳回值都是Object。 通過Object類的getClass()方法取得
<span style="color:#000000;">class Person{} public class TestDemo{ public static void main(String[] args) throws Exception{Person per = new Person();Class<?> cls = per.getClass();System.out.println(cls.getName());}}</span>
使用“類.Class”取得
<span style="font-size:12px;"> class Person{} public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Person.class;System.out.println(cls.getName());}}</span>
使用Class類內部定義的一個static方法
取得Class類對象:public static Class<?>forName(String className) throws ClassNotFoundException
class Person{} public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象System.out.println(cls.getName());}}
2.通過反射執行個體化對象
通過反射執行個體化對象:public T newInstance () throws InstantiationException,IllegalAccessException
class Person{ public String toString(){ return "Person Class Instance."; } } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Object obj = cls.newInstance(); //執行個體化對象,和使用關鍵字new一樣Person per = (Person) obj ; //向下轉型System.out.println(per);} }
範例:原廠模式
<span style="font-size:12px;">interface Fruit{public void eat();}class Apple implements Fruit{public void eat(){System.out.println("吃蘋果。");}}class Factory{public static Fruit getInstance(String className){if("apple".equals(className)){return new Apple();}return null;}}public class FactoryDemo {public static void main(String[] args) {Fruit f = Factory.getInstance("apple");f.eat();}}</span>
在這個工廠設計模式之中有一個最大的問題:如果現在介面的子類增加了,那麼工廠類肯定需要修改,這是它所面臨的最大問題,而這個最大問題造成的關鍵性病因是new,那麼如果說現在不使用關鍵字new了,變為了反射機制呢。
interface Fruit{public void eat();}class Apple implements Fruit{public void eat(){System.out.println("吃蘋果。");}}class Orange implements Fruit{public void eat(){System.out.println("吃橘子。");}}class Factory{public static Fruit getInstance(String className){Fruit f = null ;try {f = (Fruit)Class.forName(className).newInstance();} catch (Exception e) {e.printStackTrace();} return f ;}}public class FactoryDemo {public static void main(String[] args) {Fruit f = Factory.getInstance("Orange");f.eat();}}
3.調用構造方法
方法名稱 傳回值類型 說明
1
getConstructors()
Constructor數組
擷取所有許可權為public的構造方法
2
getConstructor(Class<?>…parameterTypes)
Constructor對象
擷取許可權為public的指定構造方法
3
getDeclaredConstructors()
Constructor數組
獲得所有構造方法,按聲明順序返回
4
getDeclaredConstructor(Class<?>…parameterTypes)
Constructor對象
獲得指定的構造方法
<span style="font-size:12px;">import java.lang.reflect.Constructor; class Person{ public Person(){} public Person(String name){} public Person(String name , int age){} } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Constructor<?> cons [] = cls.getConstructors(); //取得全部構造for(int x = 0 ; x < cons.length ; x ++){System.out.println(cons[x]);}} }</span>
範例:調用有參數的構造方法
import java.lang.reflect.Constructor; class Person{ private String name; private int age ; public Person(String name , int age){ this.name = name ; this.age = age ; } public String toString(){ return "Person [name="+name+",age="+age+"]" ; } } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象//取得指定參數類型的構造方法Constructor<?> cons = cls.getConstructor(String.class,int.class);Object obj = cons.newInstance("張三",20);//為構造方法傳遞參數System.out.println(obj); } }
4.調用普通方法
方法名稱 傳回值類型 說明
1
getMethods()
Method數組
擷取所有許可權為public的方法
2
getMethod(String name,Class<?>…parameterTypes)
Method對象
擷取許可權為public的指定方法
3
getDeclaredMethods()
Method數組
獲得所有方法,按聲明順序返回
4
getDeclaredMethod(String name,Class<?>…parameterTypes)
Method對象
獲得指定的方法
import java.lang.reflect.Constructor;import java.lang.reflect.Method; class Person{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Method met [] = cls.getMethods();for(int x = 0 ; x < met.length ; x ++){System.out.println(met[x]);} } }
取得了Method類對象之後有一個最大的功能,就是可以利用反射調用類中的方法。調用方法:
public Object invoke(Object obj,Object…args) throws IllegalAccessException,IllegalArgumentException,InyocationTargetException
import java.lang.reflect.Method; class Person{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Object obj = cls.newInstance();String attribute = "name"; //要調用類之中的屬性Method setMet = cls.getMethod("set"+initcap(attribute),String.class);//setName()Method getMet = cls.getMethod("get"+initcap(attribute));//getName()setMet.invoke(obj, "張三");//等價於:Person對象.setName("張三");System.out.println(getMet.invoke(obj)); //等價於:Person對象.getName() } public static String initcap(String str){ return str.substring(0,1).toUpperCase().concat(str.substring(1)); } }
5.調用成員
方法名稱 傳回值類型 說明
1
getFields()
Field數組
擷取所有許可權為public的成員變數
2
getField(String name)
Field對象
擷取許可權為public的指定成員變數
3
getDeclaredFields()
Field數組
獲得所有成員變數,按聲明順序返回
4
getDeclaredField(String name)
Field對象
獲得指定的構造方法
<span style="font-size:12px;">import java.lang.reflect.Field;import java.lang.reflect.Method; class Person{private String name; } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Field field [] = cls.getDeclaredFields();for(int x = 0 ; x < field.length ; x++) {System.out.println(field[x]);}} }</span>
在Field類之中提供了兩個方法: 設定屬性內容(類似於:對象.屬性 = 內容):
public void set(Object obj,Object value) throws IllegalArgumentExcepiton,IllegalAccessException ; 取得屬性內容(類似於:對象.屬性):
public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException
從類的開發要求而言,一直都強調之中類之中的屬性必須封裝,所以現在調用之前要想盡一切方法解除封裝。 解除封裝:public void setAccessible(boolean flag)throws SecurityException;
<span style="font-size:12px;">import java.lang.reflect.Field; class Person{private String name; } public class TestDemo{ public static void main(String[] args) throws Exception{Class<?> cls = Class.forName("Person");//取得Class對象Object obj = cls.newInstance(); //對象執行個體化屬性才會分配空間Field nameField = cls.getDeclaredField("name"); //找到name屬性nameField.setAccessible(true);nameField.set(obj,"張三");//Person對象.name = "張三"System.out.println(nameField.get(obj)); } }</span>
6.其他可以通過反射訪問的主要描述資訊
存取方法 傳回值類型 說明
包路徑
getPackage()
Package對象
獲得該類的存放路徑
類名稱
getName()
String對象
獲得該類的名稱
繼承類
getSuperclass()
Class對象
獲得該類的繼承的類
實現介面
getInterfaces()
Class數組
獲得該類實現的所有介面
內部類
getClasses()
getDeclaredClasses()
Class數組
獲得所有許可權為public的內部類
獲得所有內部類
內部類的聲明類
getDeclaringClass()
Class對象
如果該類為內部類,則返回它的成員類,否則返回null