Constructor類理解
這里Constructor旬迹,我們知道是構(gòu)造函數(shù)
為什么是數(shù)組形式的呢?
因?yàn)榭赡苡卸鄠€(gè)構(gòu)造
這個(gè)時(shí)候求类,我們寫一個(gè)DummyClass2奔垦, 這里有2個(gè)構(gòu)造
其他和前面一個(gè)Bean類似,有setter尸疆,getter椿猎,toString方法
這個(gè)時(shí)候,我們分別打印一下DummyClass和 DummyClass2 的 Constructor
具體打印工具方法
private static void printConstructor(Constructor<?>[] cons){
for(int i=0; i<cons.length; i++){
System.out.println(cons[i]);
}
}
具體打印方法
private void getAndPrintConstructors(Class cls){
Class<?> c1 = cls;
Constructor<?>[] cons= c1.getConstructors();
DUtils.printConstructor(cons);
}
具體簡單調(diào)用
DoConstructor doClass = new DoConstructor();
doClass.getAndPrintConstructors(DummyClass.class);
doClass.getAndPrintConstructors(DummyClass2.class);
具體我們可以看見結(jié)果
public com.aohuan.dodo.javacode.reflect.utils.DummyClass()
- - -
public com.aohuan.dodo.javacode.reflect.utils.DummyClass2(java.lang.String)
public com.aohuan.dodo.javacode.reflect.utils.DummyClass2(java.lang.String,int)
也就是寿弱,對象可以得到這個(gè)Class中犯眠,所有的構(gòu)造方法
對應(yīng)的構(gòu)造方法雌团,會(huì)通過數(shù)組返回
如果我們需要知道一個(gè)類中篇裁,有哪些構(gòu)造方法贞言,就可以這樣去做了
當(dāng)然拂苹,得到構(gòu)造,也就是為了創(chuàng)建實(shí)例挡鞍,
我們下面再一起回顧newInstance()方法
newInstance()方法法褥,深入
我們先看一下源碼
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) {
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw new InstantiationException(getName());
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
前面的判斷權(quán)限卖氨,判斷調(diào)用不在對應(yīng)的Class類型中
也就是
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class");
異常等問題的處理艇挨,我們略
下面通過getConstructor0(empty, Member.DECLARED);
獲得一個(gè) Constructor<T>残炮,在執(zhí)行方法(執(zhí)行的方法,我們后面幾節(jié)會(huì)提到)
這里對應(yīng)的getConstructor0方法
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
int which) throws NoSuchMethodException
{
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
這里大致
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
先獲得Constructor數(shù)組(這里which傳入的是Member.DECLARED雷袋,所以為false)
這樣就會(huì)拿到所有的構(gòu)造吉殃,包括非public的
再會(huì)
arrayContentsEq(parameterTypes,constructor.getParameterTypes())
for each循環(huán)去判斷
private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
if (a1 == null) {
return a2 == null || a2.length == 0;
}
if (a2 == null) {
return a1.length == 0;
}
if (a1.length != a2.length) {
return false;
}
for (int i = 0; i < a1.length; i++) {
if (a1[i] != a2[i]) {
return false;
}
}
return true;
}
這里大體的判斷邏輯
我們外面對應(yīng)的Class<?>[] empty = {};
所以辞居,走第一個(gè) return a2 == null || a2.length == 0;
我們沒有對應(yīng)的構(gòu)造(默認(rèn)的構(gòu)造楷怒,應(yīng)該是后面的邏輯添加進(jìn)去的,不會(huì)影響這里的邏輯)
這樣瓦灶,我們可以知道鸠删,當(dāng)我們不寫構(gòu)造的時(shí)候,會(huì)觸發(fā)創(chuàng)建對象
并且返回 tmpConstructor.newInstance((Object[])null);*
也就是默認(rèn)調(diào)用參數(shù)為null的構(gòu)造
換句話說贼陶,
Class的newInstance刃泡,
其實(shí)是調(diào)用的Constructor.newInstance((Object[])null);
修改構(gòu)造巧娱,測試
這個(gè)時(shí)候,我們調(diào)用 DummyClass2 的 newInstance() 試試
(因?yàn)?DummyClass2 有2個(gè)構(gòu)造方法烘贴,而對應(yīng)的Class的newInstance如果參數(shù)判斷通過的前提下禁添,傳入的也是空的構(gòu)造,這樣肯定會(huì)報(bào)錯(cuò))
我們運(yùn)行測試
/**
* 我們調(diào)用Class的getConstructor的 newInstance((Object[])null);
* 具體的結(jié)果桨踪,我們可以看見老翘,和前面DoClass類的newInstance方法結(jié)果一樣
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
private void doConstructorNewInstance1() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c1 = DummyClass.class;
DUtils.println(c1.getConstructor().newInstance((Object[])null).toString());
}
我們調(diào)用Class的getConstructor的 newInstance((Object[])null);
具體的結(jié)果,
DummyClass{age=0, name='null'}
我們可以看見锻离,和前面DoClass類的newInstance方法結(jié)果一樣
再看看調(diào)用DummyClass2的構(gòu)造方法
/**
* 我們調(diào)用Class的getConstructor的 newInstance("dodo");
* 會(huì)報(bào)錯(cuò)铺峭,因?yàn)樵创a中,只有沒有寫構(gòu)造的時(shí)候汽纠,才會(huì)按上面的流程走
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
private void doConstructorNewInstance2E() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c2 = DummyClass2.class;
DUtils.println(c2.getConstructor().newInstance("dodo").toString());
}
對應(yīng)的結(jié)果卫键,是
Exception in thread "main" java.lang.NoSuchMethodException: com.aohuan.dodo.javacode.reflect.utils.DummyClass2.<init>()
at java.lang.Class.getConstructor0(Class.java:2971)
at java.lang.Class.getConstructor(Class.java:1812)
at com.aohuan.dodo.javacode.reflect.sample1.DoConstructor.doConstructorNewInstance2E(DoConstructor.java:61)
at com.aohuan.dodo.javacode.reflect.sample1.DoConstructor.main(DoConstructor.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
可以發(fā)現(xiàn),對應(yīng)的邏輯是正確的
那如果構(gòu)造中虱朵,有多個(gè)參數(shù)怎么辦莉炉?
我們試試newInstance方法后面,帶下參數(shù)碴犬?
發(fā)現(xiàn)呢袱,Class就只有newInstance()這一個(gè)創(chuàng)建對象的方法
....
那我們回想下前面提到的Constructor類
Constructor 類 newInstance()
那我們嘗試一下對應(yīng)的 Constructor類 調(diào)用2個(gè)構(gòu)造的方法試試
/**
* DummyClass2 有2個(gè)自己的帶參數(shù)的構(gòu)造
* 如果通過getConstructors得到構(gòu)造的數(shù)組,在調(diào)用對應(yīng)的構(gòu)造翅敌,傳入?yún)?shù)即可
* @throws IllegalAccessException
* @throws InstantiationException
*/
private void doConstructorNewInstance2R1() throws IllegalAccessException, InstantiationException, InvocationTargetException {
Class<DummyClass2> c2 = DummyClass2.class;
DUtils.println(c2.getConstructors()[1].newInstance("dodo", 23).toString());
}
這個(gè)時(shí)候羞福,我們可以打印對應(yīng)的bean2
結(jié)果為:
DummyClass{age=23, name='dodo'}
這個(gè)時(shí)候,我們知道我們有2個(gè)構(gòu)造
同理蚯涮,我們可以
c2.getConstructors()[0].newInstance("dodo").toString();
拿到index為0的Constructor構(gòu)造類治专,
打印也可以得到結(jié)果
DummyClass{age=0, name='dodo'}
這里age是一般數(shù)據(jù)類型,不賦值遭顶,結(jié)果為0
具體Constructor 類的 public T newInstance(Object ... initargs)
我們就不繼續(xù)跟了
因?yàn)橐蕾嚨?ConstructorAccessor 類张峰,和今天討論的主題 有點(diǎn)遠(yuǎn)了
再加上 沒有源碼
就不繼續(xù)扯了
其他簡單說明
Constructor:
- getConstructors() : 獲取 public的 Constructor[](public)
- getDeclaredConstructors() : 獲取 所有的 Constructor[]
- getConstructor(parameterTypes) : 根據(jù) 參數(shù)類型(可變參數(shù)), 獲取具體 Constructor(public)
- getDeclaredConstructor(parameterTypes):根據(jù) 參數(shù)類型(可變參數(shù))棒旗, 獲取具體 Constructor
這里
- getConstructors()方法
- 是獲取 public的構(gòu)造函數(shù) 數(shù)組
- getDeclaredConstructors()方法
- 是獲取所有的構(gòu)造函數(shù) 數(shù)組
- getConstructor(parameterTypes) 方法
- 是根據(jù) 參數(shù)類型(可以有多個(gè)Class<?>的可變參數(shù))喘批,
- 獲取具體public的 Constructor
- getDeclaredConstructor(parameterTypes) 方法,
- 是根據(jù) 參數(shù)類型(可以有多個(gè)Class<?>的可變參數(shù))铣揉,
- 獲取具體的 Constructor
簡單總結(jié)
這里大致了解下
Class的簡單使用 和 大體作用
其他的內(nèi)容饶深,后續(xù)一起學(xué)習(xí)具體代碼,可以見
https://github.com/2954722256/use_little_demo
對應(yīng) javacode 的 Module逛拱,對應(yīng)的reflect包