天天看點

java反射機制反射

反射

1.反射機制

  • 概念:
    • 簡述:在運作狀态中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性==;這種動态擷取的資訊以及動态調用對象的方法的功能稱為java語言的反射機制。
    • 詳述:Java反射是Java被視為動态(或準動态)語言的一個關鍵性質。這個機制允許程式在運作時透過ReflectionAPIs取得任何一個已知名稱的class的内部資訊,包括其modifiers(諸如public, static等)、superclass(例如Object),實作之interfaces(例如Cloneable),也包括fields和methods的所有資訊,并可于運作時改變fields内容或喚起methods。
    • 類型資訊在jvm裡也是作為一個對象 隻保留一份

2.反射機制功能

  • 在運作時判斷任意一個對象所屬的類;在運作時構造任意一個類的對象;在運作時判斷任意一個類所具有的成員變量和方法;在運作時調用任意一個對象的方法;生成動态代理。

3. Reflection API

  • 當然JDK提供了反射API,我們可以學習裡面的方法來取得任何已知名稱的類的内部資訊。

Class對象的擷取

  • 對象的getClass()方法;
  • 類的.class(最安全/性能最好)屬性;
  • 運用Class.forName(String className)動态加載類,className需要是類的全限定名(最常用).

對象建立

  • 通過反射來生成對象的方式有兩種:
    • 使用Class對象的newInstance() 方法來建立該Class對象對應類的執行個體(這種方式要求該Class對象的對應類有預設構造器).
    • 先使用Class對象擷取指定的Constructor對象, 再調用Constructor對象的newInstance() 方法來建立該Class對象對應類的執行個體(通過這種方式可以選擇指定的構造器來建立執行個體).

從Class中擷取資訊

  • 擷取類内資訊
内容 方法 說明
構造器 類對象.getConstructors() 擷取所有public修飾的構造方法, 傳回數組
構造器 類對象.getDeclareConstructors() 擷取本類所有構造方法,傳回數組
構造器 類對象.getConstructor(參數) 擷取指定的構造方法,傳回對象
構造器 類對象.getConstructor() 擷取無參構造,傳回對象
包含的方法 類對象.getMethods() 擷取所有public方法,包括繼承的 傳回數組
包含的方法 類對象.getDeclaredMethods() 擷取本類的所有方法,傳回數組
包含的方法 類對象.getMethod(String name, Class<?>… parameterTypes) 擷取指定的公共方法 ,傳回對象
包含的方法 getDeclaredMethod(String name, Class<?>… parameterTypes) 傳回一個Method對象,該對象反映此Class對象表示的類或接口的指定聲明方法 。
擷取屬性資訊 類對象.getFields() 擷取所有的公共屬性 (包括繼承)
擷取屬性資訊 類對象.getDeclareFields() 擷取本類屬性
擷取屬性資訊 類對象.getField(屬性名) 根據屬性名找屬性 公共的 包括繼承
擷取屬性資訊 類對象.getDeclaredField(屬性名)

本類所有屬性

  • 上面的僅是一些使用基礎API,具體的請參照Reflection API

4.調用方法

  • 當擷取到某個類對應的Class對象之後, 就可以通過該Class對象的getMethod來擷取一個Method數組或Method對象.每個Method對象對應一個方法,在獲得Method對象之後,就可以通過調用invoke方法來調用該Method對象對應的方法.
    • 缺點:調用複雜,效率底
    • 優點:可以調用私有方法

5.setAccessible方法(性能)

  • Method/Constructor/Field/Element都繼承了AccessibleObject,AccessibleObject類中有一個setAccessible方法
  • 該方法有兩個作用:
    • 啟用/禁用通路安全檢查開關:值為true,則訓示反射的對象在使用時取消Java語言通路檢查;值為false,則訓示應該實施Java語言的通路檢查;
    • 可以禁止安全檢查, 提高反射的運作效率.

6.代碼–友善了解

代碼摘自大神部落格敬業的小碼哥

package fanshe;
/**
 * 擷取Class對象的三種方式
 * 1 Object ——> getClass();
 * 2 任何資料類型(包括基本資料類型)都有一個“靜态”的class屬性
 * 3 通過Class類的靜态方法:forName(String  className)(常用)
 *
 */
public class Fanshe {
	public static void main(String[] args) {
		//第一種方式擷取Class對象  
		Student stu1 = new Student();//這一new 産生一個Student對象,一個Class對象。
		Class stuClass = stu1.getClass();//擷取Class對象
		System.out.println(stuClass.getName());
		
		//第二種方式擷取Class對象
		Class stuClass2 = Student.class;
		System.out.println(stuClass == stuClass2);//判斷第一種方式擷取的Class對象和第二種方式擷取的是否是同一個
		
		//第三種方式擷取Class對象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字元串必須是真實路徑,就是帶包名的類路徑,包名.類名
			System.out.println(stuClass3 == stuClass2);//判斷三種方式是否擷取的是同一個Class對象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

```java
注意:在運作期間,一個類,隻有一個Class對象産生。
三種方式常用第三種,第一種對象都有了還要反射幹什麼。第二種需要導入類的包,依賴太強,不導包就抛編譯錯誤。一般都第三種,一個字元串可以傳入也可寫在配置檔案中等多種方法。


```java

package fanshe;
 
public class Student {
	
	//---------------構造方法-------------------
	//(預設的構造方法)
	Student(String str){
		System.out.println("(預設)的構造方法 s = " + str);
	}
	
	//無參構造方法
	public Student(){
		System.out.println("調用了公有、無參構造方法執行了。。。");
	}
	
	//有一個參數的構造方法
	public Student(char name){
		System.out.println("姓名:" + name);
	}
	
	//有多個參數的構造方法
	public Student(String name ,int age){
		System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,以後解決。
	}
	
	//受保護的構造方法
	protected Student(boolean n){
		System.out.println("受保護的構造方法 n = " + n);
	}
	
	//私有構造方法
	private Student(int age){
		System.out.println("私有的構造方法   年齡:"+ age);
	}
 
}
package fanshe;
 
import java.lang.reflect.Constructor;
 
 
/*
 * 通過Class對象可以擷取某個類中的:構造方法、成員變量、成員方法;并通路成員;
 * 
 * 1.擷取構造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"構造方法
            public Constructor[] getDeclaredConstructors():擷取所有的構造方法(包括私有、受保護、預設、公有)
     
 * 		2).擷取單個的方法,并調用:
 * 			public Constructor getConstructor(Class... parameterTypes):擷取單個的"公有的"構造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):擷取"某個構造方法"可以是私有的,或受保護、預設、公有;
 * 		
 * 			調用構造方法:
 * 			Constructor-->newInstance(Object... initargs)
 */
public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1.加載Class對象
		Class clazz = Class.forName("fanshe.Student");
		
		
		//2.擷取所有公有構造方法
		System.out.println("**********************所有公有構造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		
		System.out.println("************所有的構造方法(包括:私有、受保護、預設、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("*****************擷取公有、無參的構造方法*******************************");
		Constructor con = clazz.getConstructor(null);
		//1>、因為是無參的構造方法是以類型是一個null,不寫也可以:這裡需要的是一個參數的類型,切記是類型
		//2>、傳回的是描述這個無參構造函數的類對象。
	
		System.out.println("con = " + con);
		//調用構造方法
		Object obj = con.newInstance();
	//	System.out.println("obj = " + obj);
	//	Student stu = (Student)obj;
		
		System.out.println("******************擷取私有構造方法,并調用*******************************");
		con = clazz.getDeclaredConstructor(char.class);
		System.out.println(con);
		//調用構造方法
		con.setAccessible(true);//暴力通路(忽略掉通路修飾符)
		obj = con.newInstance('男');
	}
	
}

           
  • 輸出
**********************所有公有構造方法*********************************
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
************所有的構造方法(包括:私有、受保護、預設、公有)***************
private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
fanshe.Student(java.lang.String)
*****************擷取公有、無參的構造方法*******************************
con = public fanshe.Student()
調用了公有、無參構造方法執行了。。。
******************擷取私有構造方法,并調用*******************************
public fanshe.Student(char)
姓名:男

           

其他代碼還請參考上面大神的部落格:多多練習

繼續閱讀