Java類反射(能力更上一臺階,Java跳躍)

YX_blog發表於2015-09-02

如果你屬於初級學習者,當你看類反射之後,說明你的程式設計能力又升級了!

什麼是類反射:

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為Java語言的反射機制。

反射(Reflection)是Java程式開發語言的特徵之一,它允許執行中的Java程式對自身進行檢查, 也稱自審,並能直接操作程式的內部屬性。例如,使用它能獲得Java類中各成員的名稱並顯示出來。

Java的這一能力在實際應用中應用得很多,在其它的程式語言中根本就不存在這一牲。例如,Pascal、C或者C++中就沒有辦法在程式中獲得函式定義相關的資訊。
JavaBean是類反射的實際應用之一,它能讓一些工具視覺化的操作軟體元件。這些工具通過類反射動態的載入並取得Java元件(類)的屬性。後面學習的各種框架,基本上都會有反射的使用。

首先舉個例子:

api

<span style="font-size:18px;">/**
 * 
 */
package cn.hncu.reflect.test1.api;

/**
 * @author xinxin
 *
 */
public interface Intfaceebo {
	public void work();
}</span>
UsbFactory

<span style="font-size:18px;">/**
 * 
 */
package cn.hncu.reflect.test1.Factory;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import cn.hncu.reflect.test1.api.Intfaceebo;
import cn.hncu.reflect.test1.imp.Imp;

/**
 * @author xinxin
 *
 */
public class USbFatory {
	public static  Intfaceebo getUsb(){
//		S<span style="color:#000099;">tring name1 ="cn.hncu.reflect.test1.imp.Imp";
//		String name2 ="cn.hncu.reflect.test1.imp.Imp2";</span>
		try {
			// 通過修改 name  就可以呼叫不同的類,實現了 解耦
			//name 不需要依靠類了,只需要路徑名就可以獲得該類的所有資訊
			<span style="color:#ff0000;">//此處手動改麻煩,還可以 過修改屬性檔案(這樣寫就比較大了,當然修改屬性可以用介面,讓使用者自己進行修噶</span>)
			 Properties p =new Properties();
			 File file =new File("properties.cog");
			 if(!file.exists()){
				 file.createNewFile();
			 }
			 FileInputStream files =new FileInputStream(file);//配置檔案需要 IO流
			 p.load(files);//讀檔案中的資料
			<span style="color:#ff0000;">String  name =  p.getProperty("name").trim();//從配置檔案中取出來
			Class clazz=Class.forName(name);//字串傳過來的 進行類反射
			Intfaceebo c=(Intfaceebo) clazz.newInstance();//獲得類反射之後的物件</span>
			return c;
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		
		return  null;
	}
	public static void main(String[] args) {
		//1,
		//String name1 ="cn.hncu.reflect.test1.imp.Imp";
		//(當Class clazz=Class.forName(name1);)work1  is Working
//		USbFatory.getUsb().work();//執行結果 work1  is Working
		
		// 2,String name2 ="cn.hncu.reflect.test1.imp.Imp2";
		//Class clazz=Class.forName(name2);
//		USbFatory.getUsb().work();// work2  is Working
//		採用配置檔案寫之後
		USbFatory.getUsb().work();
		//name =cn.hncu.reflect.test1.imp.Imp  //work1  is Working

//		name =cn.hncu.reflect.test1.imp.Imp2 //work2  is Working

		
		
	}

}
</span>

imp包

<span style="font-size:18px;">/**
 * 
 */
package cn.hncu.reflect.test1.imp;

import cn.hncu.reflect.test1.api.Intfaceebo;

/**
 * @author xinxin
 *
 */
public class Imp implements Intfaceebo {

	
	public void work() {
		System.out.println("work1  is Working");

	}

}
</span>
imp2

<span style="font-size:18px;">/**
 * 
 */
package cn.hncu.reflect.test1.imp;

import cn.hncu.reflect.test1.api.Intfaceebo;

/**
 * @author xinxin
 *
 */
public class Imp2 implements Intfaceebo {

	
	public void work() {
		System.out.println("work2  is Working");//僅僅只是測試使用

	}

}</span>

這幾個類中,factory中用到了類反射,可以根據Class.forName("name")來獲得相對應的Class 物件,相關的測試以及測試的結果都在後面的註釋裡,main函式為了方便寫到了factory裡面。


反射使用的三個步驟 :

如:method

第一步:獲得你想操作的類的java.lang.Class物件。在執行中的Java程式中,用java.lang.Class類來描述類和介面等。

第二步:呼叫諸如getDeclaredMethods的方法,取得該類中定義的所有方法的列表。
第三步:使用反射的API來操作這些資訊。
 

自己寫的Instance 測試類

1,首先需要一個物件

/**
 * 
 */
package cn.hncu.reflect.test;

/**
 * @author xinxin
 *
 */
public class A {

}
,2,進行判斷(也就是呼叫Class.isInstance(),執行是都匹配

/**
 * 
 */
package cn.hncu.reflect.test;

/**
 * @author xinxin
 *
 */
public class TestInstanceof {

	/**
	 * @param args
	 */
	
	/*
	 * 驗證 instanceof 功能 通過這個函式isInstanceof
	 * 通過類反射Class 中的isInstance 判斷下
	 */
	public static void main(String[] args) {
		<span style="color:#ff0000;">System.out.println( isInstanceof(new A()));//結果 true
		System.out.println( isInstanceof(new Integer(10)));// false</span>

	}

	private static boolean  isInstanceof( Object obj) {
		boolean isT=false;
		try {
			<span style="color:#ff9900;">Class c =Class.forName("cn.hncu.reflect.test.A");//通過傳過來的字串,獲得Class型別
			isT=c.isInstance(obj);</span>
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return isT;
	}

}

獲取Class物件的三種方式

        1,通過物件的getClass方法進行獲取。這種方式需要具體的類和該類的物件,以及呼叫getClass方法。

      2,  任何資料型別(包括基本資料型別)都具備著一個靜態的屬性class,通過它可直接獲取到該型別對應的Class物件。這種方式要使用具體的類,然後呼叫類中的靜態屬性class完成,無需呼叫方法,效能更好。

  3,通過Class.forName()方法獲取。這種方式僅需使用類名,就可以獲取該類的Class物件,更有利於擴充套件。

例項演示:

/**
 * 
 */
package cn.hncu.reflect.Three;

import java.lang.reflect.Method;

/**
 * @author xinxin
 *
 */
public class ReflectThree {

	/**
	 * @param args
	 */
	//類反射必須先有類,匯入Person
	//這僅僅是獲得Class 物件
	public static void main(String[] args) {
//		getObject1();//通過物件的getClass方法進行獲取。
		//、這種方式需要具體的類和該類的物件,以及呼叫getClass方法。
		
		//2,任何資料型別(包括基本資料型別)都具備著一個靜態的屬性class,
//		通過它可直接獲取到該型別對應的Class物件。這種方式要使用具體的類,
//		然後呼叫類中的靜態屬性class完成,無需呼叫方法,效能更好。
//		getObject2();
		
		//3,通過Class.forName()方法獲取。這種方式僅需使用類名,
//		就可以獲取該類的Class物件,更有利於擴充套件。、
	//	getObject3();
		
		//4 小小的先實驗一下 獲得類反射出的方法
		getMethod();

	}

	

	<span style="color:#ff0000;">//1,已知具體的類 </span>
	private static void getObject1() {
		Person p =new Person("jack", 11);
		Class c =<span style="color:#ff0000;">p.getClass()</span>;//獲得Class 物件
		System.out.println(c);//class cn.hncu.reflect.Three.Person
		
	}
//任何物件包括基本資料型別都有.class 獲得Class 物件
	private static void getObject2() {
		Class c =<span style="color:#ff0000;">String.class</span>;
		System.out.println(c);//class java.lang.String
		
	}

	
	/*
	 <span style="color:#ff0000;">* 通過Class.forName(str)的方式獲取Class物件,
	 * 該方式依賴的是字串(類的名字),可以實現解耦</span>
	 */
	private static void getObject3() {
		String name ="cn.hncu.reflect.Three.Person";
		try {
			<span style="color:#ff0000;">Class  c =Class.forName(name)</span>;
			System.out.println(c);//class cn.hncu.reflect.Three.Person
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	private static void getMethod() {
		String name ="cn.hncu.reflect.Three.Person";
		try {
			Class c =Class.forName(name);
//			Object obj=c.newInstance();// 建立此 Class 物件所表示的類的一個新例項。
			Method method[] =c.getMethods();//獲得包括本身,父類的所有public方法
//			Method method[] =c.getDeclaredMethods();//獲得當前類的所有方法包括 private 等
			for(int i=0;i<method.length;i++){
				System.out.println(method[i]);
			}
			
			
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		
		
	}
	

}

前面的基礎基本介紹完了,現在開始解刨得到類物件之後:

獲取類的方法:找出一個類中定義了些什麼方法,這是一個非常有價值也非常基礎的反射用法。

程式碼演示:首先需要一個未知的類(USerModel*(在做書店管理系統時用到的,直接拷貝過來)*)

/**
 * 
 */
package cn.hncu.reflect.reflectDecompose;

import java.io.Serializable;

public class UserModel{
	private String uuid;
	private String name;
	private static int type;
	private String pwd;
	
	
	public UserModel(String uuid, String name, int type, String pwd) {
		super();
		this.uuid = uuid;
		this.name = name;
		this.type = type;
		this.pwd = pwd;
	}

	public UserModel(String uuid, int type){
		this.uuid = uuid;
		this.type = type;
	}
	public UserModel(){
	}
	private UserModel(String uuid){
		this.uuid = uuid;
	}
	public String getUuid() {
		return uuid;
	}

	public void setUuid(String uuid) {
		this.uuid = uuid;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String toString() {
		return "{"+uuid+","+name+","+type+","+pwd+"}";
	}
	
	private long privateMethod( double a){
		return (long)a;
	}
	
	void defaultMethod(int i){
		System.out.println("aa");
	}
	
}







然後就是我們的測試類:

獲取類的方法

	private static void fetchMehtod(String name) throws Exception{
		
			Class c=Class.forName(name);
			Method method[] =c.getMethods();
			for(int i=0;i<method.length;i++){
				//方法名
				Method m =method[i];
				System.out.println("name:"+m.getName());
				System.out.println(m.getDeclaringClass());
				//getDeclaringClass(),,如果此 Class 物件所表示的類或介面是另一個類的成員,則返回的 Class 物件表示該物件的宣告類。
				
				// 獲得方法出現的異常
				Class[] ex=	m.getExceptionTypes();
				for(int j=0;j<ex.length;j++){
					System.out.println("exception:"+ex[j]);
				}
				
				//引數型別
				Class par[]=m.getParameterTypes();
				for(int j=0;j<par.length;j++){
					System.out.println("Parameter:"+par[j]);
				}
				System.out.println("type:"+m.getReturnType());
	}
}

獲取類的構造器:找出一個類中定義的構造方法,構造器沒有返回型別

/**
	 * 獲取類中建構函式的資訊
	 * getConstructors() : 獲取當前類的public構造方法
	 * getDeclaredConstructors() :獲取當前類宣告的所有構造方法,包括private等其它非public方法
	 */
		private static void fetchConstror(String name2) throws Exception {
			Class c=Class.forName(name);
			
//			Constructor[] con=	c.getConstructors();
			Constructor[] con=	c.getDeclaredConstructors();
			for(int i=0;i<con.length;i++){
				//方法名
				Constructor cons=con[i];
				System.out.println("name:"+cons.getName());
				System.out.println("DeclaringClass"+cons.getDeclaringClass());
				//getDeclaringClass(),,如果此 Class 物件所表示的類或介面是另一個類的成員,則返回的 Class 物件表示該物件的宣告類。
				
				// 獲得方法出現的異常
				Class[] ex=	cons.getExceptionTypes();
				for(int j=0;j<ex.length;j++){
					System.out.println("exception:"+ex[j]);
				}
				
				//引數型別
				Class par[]=cons.getParameterTypes();
				for(int j=0;j<par.length;j++){
					System.out.println("Parameter:"+par[j]);
				}
			
	}
		
	}
獲取類的屬性欄位:找出一個類中定義了哪些屬性欄位。

private static void fetField(String name) throws Exception{
		Class c=Class.forName(name);
//		Field field[]=c.getFields();//只能訪問 public許可權
		Field field[]=c.getDeclaredFields();//獲取當前類宣告的所有構造方法,包括private等其它非public變數
		for(int i=0;i<field.length;i++){
			 Field f=field[i];
			 System.out.println("name:"+f.getName());//變數名
			 System.out.println("Declaring:"+f.getDeclaringClass());//該類的明細路徑
			 System.out.println("type:"+f.getType());// 變數的型別
			 int mod =f.getModifiers();
			 System.out.println("Modifiers::"+f);//變數的修飾符
			 System.out.println("Modifiers::"+Modifier.toString(mod));//輸出型別 如  public  private
}

一起到這裡我們已經會從獲得的類中得到未知類的資訊了,後面會有持續更新。



相關文章