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方法來調用構造器執行個體化對象;