天天看點

【Java筆記】反射機制中用Class操作的一些示範

import org.junit.Test;


public class Test_01 {
@Test
	public void Dome_05() throws InstantiationException, IllegalAccessException{
		Class cc1=Cat.class;
		Cat cat=(Cat) cc1.newInstance();//這個方法是通過類對象調用構造器來建立類的執行個體對象;
		cat.age=3;
		
	}
}
           
package Test_01;

public class Cat extends Animals{
	 String name;
	 int age;
	 int legs;
	 Cat(){}
	
}
           
成功建立Cat對象
           

我們來看一下newInstance的API解釋:

newInstance

public T newInstance()
              throws InstantiationException,
                     IllegalAccessException      
建立此 Class 對象所表示的類的一個新執行個體。如同用一個帶有一個空參數清單的

new

表達式執行個體化該類。如果該類尚未初始化,則初始化這個類。

實際上newInstance就是通過調用無參構造器來建立對象,我如果把Cat中的構造器私有化:

package Test_01;

public class Cat extends Animals{
	 String name;
	 int age;
	 int legs;
	private Cat(){}
}
           

運作時報錯

是以,用newInstance必須保證在類裡一定要有一個無參構造器;

上面是newInstance來建立對象的方法,其實和直接new對象沒有什麼很大的差別;下面我們來看一下Class的真正強大之處:

package Test_01;

public class Cat extends Animals{
	 private String name;
	 private int age;
	 private int legs;
	 private Cat(){}
	 private Cat(String name,int age,int legs){
		this.age=age;
		this.legs=legs;
		this.name=name;
	}
}
           

可以看到我完全把Cat類封裝,也沒有實行單例模式,也沒有設定get、set方法,按理來說已經沒辦法執行個體化它的對象了,但是用Class的反射機制可以通過調用方法來傳回Constructor中的方法來執行個體化它!

API:Constructor

提供關于類的單個構造方法的資訊以及對它的通路權限。 

@Test
	public void Dome_05() throws InstantiationException, IllegalAccessException, Exception, Throwable{
		Class<Cat> cc = Cat.class;
		//通過Class類中的getDeclaredConstructor可以獲得私有化的構造器
			Constructor<Cat> constructor =cc.getDeclaredConstructor(String.class,int.class,int.class);
			//把constructor的權限設成true
			constructor.setAccessible(true);
			//下面就可以通過構造器來執行個體化對象了
			Cat gaffey=constructor.newInstance("gaffey",3,4);
			System.out.println(gaffey);					
	}
           

輸出結果:[email protected]

列印出了對象的位址,說明成功建立了一個對象;注意:此時就算是建立了對象,我的Cat的成員變量仍是全部私有化的,是以也不能通過對象對成員變量進行操作;

在jdk的API中:

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
          傳回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法。 
 Constructor<?>[] getDeclaredConstructors() 
          傳回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 
           

可知,我們通過控制傳入參數的多少來控制調哪一個構造器,要注意的是,如果我們傳參數,傳入的必須是類對象,這個類不是我們通常說的類或建立的類(小寫的class),而是大寫的Class,是jdk中存在的單例模式的Class,所有的小寫的class類,都可以是這個大寫的Class類的對象,比如我們要傳入String,就應該傳入String的class屬性,用“String.class";

看一下Constructor類,裡面也有一個newInstance方法:

newInstance

public T newInstance(Object... initargs)

throws InstantiationException,

IllegalAccessException,

IllegalArgumentException,

InvocationTargetException使用此 Constructor 對象表示的構造方法來建立該構造方法的聲明類的新執行個體,并用指定的初始化參數初始化該執行個體。個别參數會自動解包,以比對基本形參,必要時,基本參數和引用參數都要進行方法調用轉換。

如果底層構造方法所需形參數為 0,則所提供的 initargs 數組的長度可能為 0 或 null。

如果構造方法的聲明類是非靜态上下文的内部類,則構造方法的第一個參數需要是封閉執行個體;請參閱Java 語言規範 第 15.9.3 節。

如果所需的通路檢查和參數檢查獲得成功并且執行個體化繼續進行,這時構造方法的聲明類尚未初始化,則初始化這個類。

如果構造方法正常完成,則傳回新建立且已初始化的執行個體。

顯然通過建構Constructor就可以調用有參的構造器了,我上面的那篇代碼中也示範了用Constructor的newInstance方法來調用構造器執行個體化對象;