一、簡(jiǎn)介
??Reflector
是整個(gè)反射器模塊的基礎(chǔ)嗜历,每個(gè)Reflector
對(duì)象都對(duì)應(yīng)一個(gè)類赊时,在其構(gòu)造函數(shù)中吨铸,根據(jù)傳入的Class對(duì)象,調(diào)用Java的反射API蛋叼,獲取并緩存反射操作需要用到的這個(gè)類的元信息焊傅。
二、成員屬性
private Class<?> type; // 對(duì)應(yīng)的Class類型
private String[] readablePropertyNames = EMPTY_STRING_ARRAY; // 可讀屬性的名稱集合狈涮,可讀屬性就是存在相應(yīng)getter方法的屬性狐胎,初始值為空數(shù)組
private String[] writeablePropertyNames = EMPTY_STRING_ARRAY; // 可寫(xiě)屬性的名稱集合,可寫(xiě)屬性就是存在相應(yīng)setter方法的屬性歌馍,初始值為空數(shù)組
private Map<String, Invoker> setMethods = new HashMap<String, Invoker>(); // 記錄了屬性相應(yīng)的setter方法握巢,key是屬性名稱,value是Invoker對(duì)象松却,其封裝了setter方法對(duì)應(yīng)的Method對(duì)象
private Map<String, Invoker> getMethods = new HashMap<String, Invoker>(); // 屬性相應(yīng)的getter方法集合暴浦,key是屬性名稱溅话,value是Invoker對(duì)象
private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>(); // 記錄了屬性相應(yīng)的setter方法的參數(shù)值類型,key是屬性名稱歌焦,value是setter方法的參數(shù)類型
private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>(); // 記錄了屬性相應(yīng)的getter方法的返回值類型飞几,key是屬性名稱,value是getter方法的返回值類型
private Constructor<?> defaultConstructor; // 記錄了默認(rèn)的構(gòu)造方法
private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>(); // 記錄了所有屬性名稱的集合独撇,key統(tǒng)一記錄成大寫(xiě)
-
type
:傳入的需要解析元信息的類屑墨,每個(gè) Reflector 對(duì)象都對(duì)應(yīng)一個(gè)類。 -
readablePropertyNames
:可讀屬性的名稱集合纷铣,一般Java Bean中屬性定義為私有卵史,要讀取屬性值,必須通過(guò) getter 方法來(lái)獲取搜立,換句話說(shuō)以躯,假如屬性有相應(yīng)的 getter 方法,我們就認(rèn)定為該屬性為可讀屬性啄踊。假如屬性名為 username 忧设,則方法名一般為 getUsername() ,假如屬性是布爾值如 open 社痛,則方法名一般為 isOpen() 见转。 -
writeablePropertyNames
:可寫(xiě)屬性的名稱集合,同樣的類似上面的蒜哀,如果屬性有相應(yīng)的 setter 方法,可認(rèn)定為可寫(xiě)屬性吏砂。 -
setMethods
:實(shí)際運(yùn)行中如將SQL執(zhí)行返回結(jié)果集映射為Java對(duì)象撵儿,設(shè)置對(duì)象屬性的操作需要反射來(lái)完成,這些操作封裝在 Invoker 對(duì)象中狐血,該對(duì)象緩存屬性對(duì)應(yīng)的 Field 對(duì)象淀歇,設(shè)置屬性值依賴該 Field 對(duì)象完成;key對(duì)應(yīng)屬性名稱匈织,value對(duì)應(yīng) Invoker 對(duì)象浪默。 -
getMethods
:同樣獲取對(duì)象屬性值需要反射來(lái)完成,原理跟上面類似缀匕,不過(guò)反射的操作由 set 變成 get 纳决。 -
setTypes
:不管是執(zhí)行SQL前參數(shù)的預(yù)編譯,還是執(zhí)行完之后將結(jié)果集映射為Java對(duì)象乡小,都需要知道屬性的類型阔加,底層的JDBC對(duì)象才知道要調(diào)用哪些相應(yīng)的方法;本屬性緩存了屬性名和屬性的 setter 方法的映射關(guān)系满钟。 -
getTypes
:同上胜榔,本屬性緩存了屬性名和屬性的 getter 方法的映射關(guān)系胳喷。 -
defaultConstructor
:傳入解析的類的默認(rèn)構(gòu)造方法,常用于通過(guò)反射創(chuàng)建Java對(duì)象夭织。 -
caseInsensitivePropertyMap
:記錄了所有屬性名稱的集合吭露,key統(tǒng)一處理成大寫(xiě),value則為屬性名尊惰。
三奴饮、構(gòu)造方法
??Reflector
的構(gòu)造方法中,會(huì)解析執(zhí)行的Class對(duì)象择浊,并填充上述集合戴卜,源碼如下:
public Reflector(Class<?> clazz) {
type = clazz; // 初始化type字段
addDefaultConstructor(clazz); // 查找clazz的默認(rèn)構(gòu)造方法(無(wú)參構(gòu)造方法),通過(guò)反射獲取所有構(gòu)造方法琢岩,通過(guò)遍歷找出參數(shù)長(zhǎng)度為0的構(gòu)造方法
addGetMethods(clazz); // 獲取clazz中的getter方法投剥,并填充getMethods集合和getTypes集合
addSetMethods(clazz); // 獲取clazz中的setter方法,并填充setMethods集合和setTypes集合
addFields(clazz); // 處理沒(méi)有g(shù)etter/setter的字段
// 根據(jù)getMethods/setMethods集合担孔,初始化可讀/寫(xiě)屬性的名稱集合
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
// 初始化caseInsensitivePropertyMap集合江锨,其中記錄了所有大寫(xiě)格式的屬性名稱
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
??首先初始化 type
屬性,然后在 addDefaultConstructor() 方法中根據(jù)傳入的Class對(duì)象的默認(rèn)構(gòu)造方法初始化 defaultConstructor
屬性糕篇,接著調(diào)用 addGetMethods() 方法填充 getMethods
和 getTypes
集合啄育,同理調(diào)用 addSetMethods() 方法填充 setMethods
和 setTypes
集合,調(diào)用 addFields() 方法去處理沒(méi)有g(shù)etter/setter的其余字段拌消,因?yàn)榈讓颖举|(zhì)是通過(guò)反射來(lái)獲取和設(shè)置屬性值挑豌,該方法也會(huì)填充上述的四個(gè)集合,最后再將收集到的屬性名根據(jù)允許獲取和設(shè)置值來(lái)填充 readablePropertyNames
和 writeablePropertyNames
集合墩崩,再將這兩個(gè)集合中的所有屬性名的大寫(xiě)作為key來(lái)填充 caseInsensitivePropertyMap
氓英。
四、方法功能
1鹦筹、addDefaultConstructor(Class<?> clazz)
【功能】獲取類的默認(rèn)構(gòu)造方法铝阐。
【源碼與注釋】
private void addDefaultConstructor(Class<?> clazz) {
// 獲取類的所有構(gòu)造方法
Constructor<?>[] consts = clazz.getDeclaredConstructors();
// 遍歷所有構(gòu)造方法
for (Constructor<?> constructor : consts) {
// 找到無(wú)參構(gòu)造方法,該方法即為默認(rèn)構(gòu)造方法
if (constructor.getParameterTypes().length == 0) {
// 構(gòu)造方法有可能被private修飾铐拐,需要設(shè)置其可以訪問(wèn)
if (canAccessPrivateMethods()) {
try {
constructor.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
// 如果無(wú)參構(gòu)造方法有訪問(wèn)的權(quán)限徘键,則賦值給defaultConstructor
if (constructor.isAccessible()) {
this.defaultConstructor = constructor;
}
}
}
}
2、canAccessPrivateMethods()
【功能】判斷系統(tǒng)安全管理器是否允許修改類的可訪問(wèn)性遍蟋。
【源碼與注釋】
// 判斷是否可以修改可訪問(wèn)性
private static boolean canAccessPrivateMethods() {
try {
// 獲取系統(tǒng)安全管理器
SecurityManager securityManager = System.getSecurityManager();
// 如果設(shè)置了安全管理器吹害,檢查是否有通過(guò)反射來(lái)訪問(wèn)protected、private的成員和方法的權(quán)限
if (null != securityManager) {
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
} catch (SecurityException e) {
// 如果沒(méi)有權(quán)限匿值,則權(quán)限檢查會(huì)拋出異常赠制,返回false表示不允許訪問(wèn)私有方法
return false;
}
// 如果未設(shè)置安全管理器,或者有指定權(quán)限,則返回true表示允許訪問(wèn)私有方法
return true;
}
3钟些、addGetMethods()
【功能】獲取類的 getter 方法并填充 getMethods
和 getTypes
集合烟号。
【源碼與注釋】
private void addGetMethods(Class<?> cls) {
// (1)定義屬性名和對(duì)應(yīng)getter方法的映射
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
// (2)獲取當(dāng)前類及其父類中定義的所有方法
Method[] methods = getClassMethods(cls);
// (3)遍歷所有方法,篩選出 getter 方法并添加到 conflictingGetters 中
for (Method method : methods) {
String name = method.getName();
// 篩選出getter方法: 一般屬性名為aaBb對(duì)應(yīng)的getter方法為getAaBb()
// 如果屬性是布爾值政恍,則對(duì)應(yīng)的getter方法為isAaBb()
// 如果子類重寫(xiě)覆蓋了父類getter方法導(dǎo)致方法簽名不一致
// eg:
// 父類定義: List<String> getList() 方法簽名為: java.util.List<String>#getList
// 子類定義: ArrayList<String> getList() 方法簽名為: java.util.ArrayList<String>#getList
// 我們要取的肯定是返回參數(shù)類型更加具體的方法汪拥,但是方法簽名不一致導(dǎo)致沖突,就先將屬性名和對(duì)應(yīng)的沖突方法緩存到conflictingGetters
// 再交給resolveGetterConflicts()方法進(jìn)一步處理
// (3.1)以 get 和 is 開(kāi)頭篙耗,并且方法名長(zhǎng)度分別長(zhǎng)于 3 和 2 才表明這是個(gè) getter 方法
if (name.startsWith("get") && name.length() > 3) {
// (3.2)只有方法參數(shù)個(gè)數(shù)為0的方法才是 getter 方法
if (method.getParameterTypes().length == 0) {
// (3.3)根據(jù)方法名獲取屬性名
name = PropertyNamer.methodToProperty(name);
// (3.4)屬性名和方法的映射添加到 conflictingGetters 中
addMethodConflict(conflictingGetters, name, method);
}
} else if (name.startsWith("is") && name.length() > 2) {
if (method.getParameterTypes().length == 0) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
}
}
}
// (4)解決簽名不同但是方法重復(fù)的 getter 方法迫筑,一般屬性的 getter 只需要有一個(gè)即可
resolveGetterConflicts(conflictingGetters);
}
【解析】
(1)定義屬性名和 getter 方法的映射,因?yàn)樽宇惪赡苤貙?xiě)父類方法宗弯,比如返回值類型更加具體脯燃,所以映射的值是一個(gè)列表。
(2)調(diào)用 #getClassMethods()
方法來(lái)獲取類的所有方法蒙保,包括實(shí)現(xiàn)接口定義的方法辕棚、繼承自父類的方法,并沿著繼承鏈向上追溯邓厕,具體實(shí)現(xiàn)可閱讀下面關(guān)于該方法的詳解逝嚎。
(3)遍歷所有方法,篩選出 getter 方法
- (3.1)只有形如
getXxx()
和isYyy()
的方法才是 getter 方法 - (3.2)getter 方法的參數(shù)個(gè)數(shù)應(yīng)該為0
- (3.3)根據(jù)方法名獲得屬性名
- (3.4)屬性名和方法的映射添加到 conflictingGetters 中详恼,如果屬性名第一次添加方法补君,則創(chuàng)建List,否則添加到已經(jīng)創(chuàng)建的List中昧互,源碼如下:
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
// 獲取List
List<Method> list = conflictingMethods.get(name);
// List為空挽铁,說(shuō)明該屬性是第一次,先創(chuàng)建List硅堆,再將List添加到conflictingMethods中
if (list == null) {
list = new ArrayList<Method>();
conflictingMethods.put(name, list);
}
// 往Method List中添加Method
list.add(method);
}
(4)調(diào)用 #resolveGetterConflicts(Map<String, List<Method>>)
方法解決簽名不同但是方法重復(fù)的 getter 方法的問(wèn)題屿储,一般屬性的 getter 只需要有一個(gè)即可,詳解參見(jiàn)下面對(duì)該方法的介紹渐逃。
4、getClassMethods(Class<?> cls)
【功能】獲取類cls及其超類中聲明的方法民褂,及其實(shí)現(xiàn)的接口方法茄菊,使用本方法而不是更簡(jiǎn)單的 Class.getMethods()
是因?yàn)槲覀円蚕氆@取被聲明為 private 的方法。
【源碼與注釋】
private Method[] getClassMethods(Class<?> cls) {
// (1)用于記錄指定類中定義的全部方法的唯一簽名以及對(duì)應(yīng)的Method對(duì)象
Map<String, Method> uniqueMethods = new HashMap<String, Method>();
// (2)表示當(dāng)前在while循環(huán)體中被解析聲明方法所屬的類赊堪,將從cls到cls的父類面殖,最終為Object類
Class<?> currentClass = cls;
while (currentClass != null) {
// (3)記錄currentClass這個(gè)類中定義的全部方法
// PS.只能獲取類內(nèi)定義的普通方法,對(duì)于繼承的方法無(wú)法通過(guò)反射獲取
addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());
// (4)我們也要尋找接口方法哭廉,因?yàn)轭惪赡苁浅橄蟮募沽牛赡軐?shí)現(xiàn)了接口方法,這些方法無(wú)法通過(guò)上面的反射獲取
// we also need to look for interface methods -
// because the class may be abstract
Class<?>[] interfaces = currentClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
addUniqueMethods(uniqueMethods, anInterface.getMethods());
}
// (5)獲取父類,繼續(xù)循環(huán)辽幌,獲取從父類繼承的方法
currentClass = currentClass.getSuperclass();
}
// (6)將 uniqueMethods 中的值即方法取出來(lái)放 methods 集合中
Collection<Method> methods = uniqueMethods.values();
// (7)將 methods 集合轉(zhuǎn)化為 Method 數(shù)組返回
return methods.toArray(new Method[methods.size()]);
}
【解析】
(1)定義局部變量 uniqueMethods:存儲(chǔ)方法簽名和方法的映射關(guān)系增淹,方法簽名可以看成是每個(gè)方法的唯一標(biāo)識(shí),其組成規(guī)則可以看下面關(guān)于 #addUniqueMethods()
方法的詳解乌企。
(2)定義局部變量 currentClass:表示當(dāng)前被解析方法的類虑润,將一直沿著繼承鏈向上循環(huán),從cls到cls的父類加酵,最終為Object類拳喻。
(3)調(diào)用 #addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods)
方法記錄當(dāng)前類中定義的所有方法到 uniqueMethods 中,其源碼實(shí)現(xiàn)如下:
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
for (Method currentMethod : methods) {
// (3.1)過(guò)濾掉橋接方法猪腕,橋接方法不是類中定義的方法冗澈,而是編譯器為了兼容自動(dòng)生成的方法
if (!currentMethod.isBridge()) {
// (3.2)獲取方法簽名
// 通過(guò)Reflector.getSignature()方法得到的方法簽名是: 返回值類型#方法名稱:參數(shù)類型列表。
// 例如陋葡,Reflector.getSignature(Method)方法的唯一簽名是:
// java.lang.String#getSignature:java.lang.reflect.Method
// 通過(guò)Reflector.getSignature()方法得到的方法簽名是全局唯一的亚亲,可以作為該方法的唯一標(biāo)識(shí)
String signature = getSignature(currentMethod);
// (3.3)檢測(cè)在子類中是否已經(jīng)添加過(guò)該方法,如果在子類中已經(jīng)添加過(guò)脖岛,則表示子類覆蓋了該方法朵栖,
// 無(wú)須再想uniqueMethods集合中添加該方法了
// check to see if the method is already known
// if it is known, then an extended class must have
// overridden a method
if (!uniqueMethods.containsKey(signature)) {
if (canAccessPrivateMethods()) {
try {
currentMethod.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
// (3.4)記錄該簽名和方法的對(duì)應(yīng)關(guān)系
uniqueMethods.put(signature, currentMethod);
}
}
}
}
- (3.1)首先過(guò)濾掉橋接方法,所謂橋接方法柴梆,就是編譯器為了兼容JDK自動(dòng)生成而不是代碼中定義的方法
- (3.2)獲取方法簽名陨溅,源碼如下:
private String getSignature(Method method) {
StringBuilder sb = new StringBuilder();
// 返回類型
Class<?> returnType = method.getReturnType();
if (returnType != null) {
sb.append(returnType.getName()).append('#');
}
// 方法名
sb.append(method.getName());
// 方法參數(shù)類型
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (i == 0) {
sb.append(':');
} else {
sb.append(',');
}
sb.append(parameters[i].getName());
}
return sb.toString();
}
其組成規(guī)則為:方法返回值類型#方法名:參數(shù)1類型,參數(shù)2類型,參數(shù)3類型,...,參數(shù)名n類型
eg:void#addUniqueMethods:Map<String, Method>,Method[]
- (3.3)因?yàn)樽宇惪赡苤貙?xiě)父類的方法,因此當(dāng)前類為上一次循環(huán)類的父類時(shí)绍在,有可能父類被子類重寫(xiě)的方法的簽名跟子類是一樣的门扇,這種情況以子類中聲明的方法為準(zhǔn),如果方法是私有的偿渡,則添加訪問(wèn)權(quán)限臼寄。
- (3.4)將方法簽名和方法的映射添加到 uniqueMethods 中。
(4)獲取當(dāng)前類實(shí)現(xiàn)的接口溜宽,并遍歷接口調(diào)用 #addUniqueMethods(Map<String, Method>, Method[])
獲得接口中定義的方法吉拳。
(5)獲取父類,繼續(xù)循環(huán)适揉,獲取從父類繼承的方法留攒。
(6)循環(huán)結(jié)束后,將 uniqueMethods 中的值即獲取到的類的所有方法放到 methods 集合中嫉嘀。
(7)將 methods 集合轉(zhuǎn)化為 Method 數(shù)組返回炼邀。
5、resolveGetterConflicts(Map<String, List<Method>> conflictingGetters)
【功能】解決一個(gè)屬性有多個(gè) getter 方法的問(wèn)題剪侮,并調(diào)用 #addGetMethod(String name, Method method)
方法真正填充 getMethods
和 getTypes
集合拭宁。
【源碼與注釋】
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
// (1)對(duì)每個(gè)屬性的方法逐個(gè)處理
for (String propName : conflictingGetters.keySet()) {
List<Method> getters = conflictingGetters.get(propName);
Iterator<Method> iterator = getters.iterator();
Method firstMethod = iterator.next();
// (2)該字段只有一個(gè)getter方法,沒(méi)有沖突,直接添加到getMethods集合并填充getTypes集合
if (getters.size() == 1) {
addGetMethod(propName, firstMethod);
} else {
// (3)同一屬性名稱存在多個(gè)getter方法杰标,則需要對(duì)比這些getter方法的返回值兵怯,選擇getter方法
// 迭代過(guò)程中的臨時(shí)變量,用于記錄迭代到目前為止在旱,最適合作為getter方法的Method
Method getter = firstMethod;
// (3.1)記錄返回值類型
Class<?> getterType = firstMethod.getReturnType();
while (iterator.hasNext()) {
Method method = iterator.next();
Class<?> methodType = method.getReturnType();
if (methodType.equals(getterType)) {
// (3.2)返回值相同摇零,實(shí)際上沒(méi)有沖突,證明方法簽名生成那個(gè)可能有問(wèn)題了桶蝎,拋出異常
throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass()
+ ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
} else if (methodType.isAssignableFrom(getterType)) {
// (3.3)假如判斷結(jié)果為true驻仅,表示methodType是getterType的繼承父類或?qū)崿F(xiàn)的接口
// 當(dāng)前最合適的方法(getter)的返回值是當(dāng)前方法(method)返回值的子類,什么都不做登渣,當(dāng)前最適合的方法依然不變
// OK getter type is descendant
} else if (getterType.isAssignableFrom(methodType)) {
// (3.4)當(dāng)前方法的返回值是當(dāng)前最適合的方法的返回值的子類噪服,更新臨時(shí)變量getter,當(dāng)前的getter方法成為最適合的getter方法
getter = method;
getterType = methodType;
} else {
// (3.5)返回值相同胜茧,二義性粘优,拋出異常
throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass()
+ ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
}
}
// (4)while循環(huán)結(jié)束篩選出最合適的方法之后,調(diào)用addGetMethod()方法填充getMethods和getTypes集合
addGetMethod(propName, getter);
}
}
}
【解析】
(1)遍歷逐個(gè)處理每個(gè)屬性呻顽,因?yàn)樽宇惪梢愿采w重寫(xiě)父類的方法雹顺,所以一個(gè)屬性可能有多個(gè) getter 方法
(2)如果屬性只有一個(gè) getter 方法,沒(méi)有沖突廊遍,則直接調(diào)用 #addGetMethod(String name, Method method)
方法填充處理嬉愧。
(3)同一屬性可能有多個(gè) getter 方法,定義局部變量 getter 存儲(chǔ)當(dāng)前最合適的getter
- (3.1)定義局部變量 getterType喉前,記錄 getter 的返回類型没酣。
- (3.2)因?yàn)?getter 方法名相同,且不帶參數(shù)卵迂,所以如果子類和父類方法返回值類型完全相同裕便,說(shuō)明要么子類畫(huà)蛇添足方法跟父類相同如下所示,要么證明生成方法簽名的方法可能有問(wèn)題见咒,此時(shí)拋出異常偿衰。
// 父類
public class SupClass {
private List userList;
public List getUserList() {
return userList;
}
}
// 子類
public class SubClass {
private List userList;
public List getUserList() {
return userList;
}
}
- (3.3)如果遍歷到的其他 getter 方法的返回值類型是當(dāng)前最適合的 getter 方法返回值類型的父類,則
getter
依然是最合適的方法改览,舉例如下:
// 父類
public class SupClass() {
private List userList;
// 當(dāng)前遍歷到的method哎垦,methodType為L(zhǎng)ist
public List getUserList() {
return userList;
}
}
// 子類
public class SubClass {
private ArrayList userList;
// 當(dāng)前遍歷篩選到的最合適的getter,getterType為ArrayList
public ArrayList getUserList() {
return userList;
}
}
- (3.4)跟上面的情況反過(guò)來(lái)恃疯,只是此時(shí)
getter
為父類的 getUserList 方法,getterType
為 List墨闲,這時(shí)遍歷到更合適的子類的方法今妄,因?yàn)槠浞祷仡愋透泳唧w,所以更新替換getter
和getterType
。 - (3.5)如果不同的 getter 只是剛好方法名相同盾鳞,實(shí)際上返回類型既不完全相同犬性,也沒(méi)有繼承派生關(guān)系,則證明開(kāi)發(fā)人員寫(xiě)的類不符合 JavaBean 的規(guī)范腾仅,此時(shí)直接拋出異常乒裆。
- (4)找到最合適的 getter 方法之后,調(diào)用
#addGetMethod(String name, Method method)
方法填充處理推励。
6鹤耍、addGetMethod(String name, Method method)
【功能】篩選合法的屬性名,將方法封裝成 MethodInvoker
作為 value验辞,屬性名作為 key 填充 getMethods
集合稿黄;解析方法返回的真正類型(因?yàn)橛锌赡軒Х盒汀⑼ㄅ浞龋┳鳛?value跌造,屬性名作為 key 填充 getTypes
集合杆怕。
【源碼與注釋】
private void addGetMethod(String name, Method method) {
// (1)篩選過(guò)濾掉非法的屬性名
if (isValidPropertyName(name)) {
// (2)將屬性名以及對(duì)應(yīng)的MethodInvoker對(duì)象添加到getMethods集合中,MethodInvoker是對(duì)Method對(duì)象反射操作的封裝
getMethods.put(name, new MethodInvoker(method));
// (3)因?yàn)榉椒ǚ祷刂抵锌赡軒в蟹盒涂翘埃琫g: List<T>
// 所以通過(guò)TypeParameterResolver.resolveReturnType()方法將類型信息解析到Type對(duì)象中
Type returnType = TypeParameterResolver.resolveReturnType(method, type);
// (4)將屬性名稱和對(duì)應(yīng)的返回值類型添加到getTypes集合中保存
getTypes.put(name, typeToClass(returnType));
}
}
【解析】
(1)調(diào)用 #isValidPropertyName(String)
方法過(guò)濾出合理的屬性名陵珍,合理的標(biāo)準(zhǔn)是:
- 屬性名不以
$
開(kāi)頭 + 屬性名不為serialVersionUID
(類實(shí)現(xiàn)序列化接口要定義的屬性)+ 屬性名不為class
其源碼如下:
private boolean isValidPropertyName(String name) {
return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
}
(2)根據(jù) method 對(duì)象封裝創(chuàng)建 MethodInvoker
作為 value,屬性名為 key 填充 getMethods
集合违施。
(3)調(diào)用 #TypeParameterResolver.resolveReturnType(Method method, Type srcType)
解析返回值的具體類型(關(guān)于該工具類的解析過(guò)程可參考:[MyBatis源碼分析 - 反射器模塊 - 組件四] TypeParameterResolver
)互纯,并調(diào)用 #typeToClass(Type src)
方法將返回類型對(duì)應(yīng)的 Type 對(duì)象轉(zhuǎn)化為 Class 對(duì)象并填充 getTypes
集合。醉拓,其源碼如下:
private Class<?> typeToClass(Type src) {
Class<?> result = null;
// 普通類型伟姐,直接使用類
if (src instanceof Class) {
result = (Class<?>) src;
// 參數(shù)化類型,使用原始類型亿卤,如參數(shù)化類型List<String>的原始類型是List
} else if (src instanceof ParameterizedType) {
result = (Class<?>) ((ParameterizedType) src).getRawType();
// 泛型數(shù)據(jù)類型愤兵,形如A<T>[]或T[],前者的數(shù)組元素類型是ParameterizedType排吴,后者是TypeVariable
// 當(dāng)然秆乳,經(jīng)過(guò)TypeParameterResolver的處理,里面的泛型已被解析為具體類型钻哩,如List<String>[]屹堰、String[]
} else if (src instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) src).getGenericComponentType();
// 數(shù)組元素已經(jīng)是一個(gè)具體類型,直接返回形如String[]對(duì)應(yīng)的Class對(duì)象即可
if (componentType instanceof Class) {
result = Array.newInstance((Class<?>) componentType, 0).getClass();
} else {
// 數(shù)組元素依然不是一個(gè)普通類型街氢,如List<String>[]扯键,遞歸調(diào)用typetoClass方法處理,如上會(huì)返回List
// 最終返回的result為L(zhǎng)ist[]
Class<?> componentClass = typeToClass(componentType);
result = Array.newInstance((Class<?>) componentClass, 0).getClass();
}
}
if (result == null) {
result = Object.class;
}
return result;
}
7珊肃、addSetMethods(Class<?> cls)
【功能】獲取類的 setter 方法荣刑,并提取屬性名馅笙,填充 setMethods
和 setTypes
集合。
【源碼與注解】
private void addSetMethods(Class<?> cls) {
// 屬性名與其 setter 方法的映射
Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
// 獲取類的所有方法
Method[] methods = getClassMethods(cls);
// 遍歷所有方法
for (Method method : methods) {
String name = method.getName();
// 篩選出符合 setter 方法名規(guī)則的方法
if (name.startsWith("set") && name.length() > 3) {
// setter 方法的參數(shù)個(gè)數(shù)應(yīng)該為1
if (method.getParameterTypes().length == 1) {
// 根據(jù)方法名提取出屬性名厉亏,eg: getUser() => user
name = PropertyNamer.methodToProperty(name);
// 將屬性與其 setter 方法的映射添加到conflictingSetters中
addMethodConflict(conflictingSetters, name, method);
}
}
}
// 解決同個(gè)屬性名有多個(gè)沖突的 setter 方法的問(wèn)題
resolveSetterConflicts(conflictingSetters);
}
【解析】
??跟 #addGetMethods(Class<?> cls)
方法的處理過(guò)程大同小異董习,setter 方法不管參數(shù)類型是否布爾值,方法名都形如 setXxx爱只,并且參數(shù)個(gè)數(shù)必須為1皿淋,然后提取屬性名,添加到 conflictingSetters
映射中恬试,最后調(diào)用 #resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)
方法處理 setter 方法沖突窝趣。
8、resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)
【功能】為類的每個(gè)屬性挑選出最合適的 setter 方法忘渔,并調(diào)用 #addSetMethod(String name, Method method)
方法處理填充 setMethods
和 setTypes
集合高帖。
【源碼與注解】
private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
// (1)逐個(gè)處理每個(gè)屬性,為其找到最合適的 setter 方法畦粮,因?yàn)樽宇惪梢愿采w父類的方法散址,所以一個(gè)屬性可能有多個(gè) setter 方法
for (String propName : conflictingSetters.keySet()) {
List<Method> setters = conflictingSetters.get(propName);
Method firstMethod = setters.get(0);
// (2)只有一個(gè) setter 方法,直接調(diào)用addSetMethod方法填充setMethods和setTypes集合
if (setters.size() == 1) {
addSetMethod(propName, firstMethod);
} else {
// (3)獲取正在篩選 setter 方法的屬性的 getter 方法的返回類型宣赔,應(yīng)該跟 setter 的參數(shù)類型一致
Class<?> expectedType = getTypes.get(propName);
// (3.1)屬性有setter卻沒(méi)有g(shù)etter方法预麸,存在二義性,不符合JavaBeans的規(guī)范儒将,直接拋出異常
if (expectedType == null) {
throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
"specification and can cause unpredicatble results.");
} else {
Iterator<Method> methods = setters.iterator();
Method setter = null;
while (methods.hasNext()) {
Method method = methods.next();
// (3.2)setter參數(shù)個(gè)數(shù)應(yīng)該只有一個(gè)并且參數(shù)類型跟getter方法的返回值類型相同吏祸,不符合則循環(huán)
if (method.getParameterTypes().length == 1
&& expectedType.equals(method.getParameterTypes()[0])) {
setter = method;
break;
}
}
// (4)如果循環(huán)結(jié)束還沒(méi)找到setter方法,則拋出異常
if (setter == null) {
throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
"specification and can cause unpredicatble results.");
}
// (5)while循環(huán)結(jié)束篩選出最合適的方法之后钩蚊,調(diào)用addSetMethod()方法填充setMethods和setTypes集合
addSetMethod(propName, setter);
}
}
}
}
【詳解】
(1)(2)步的處理與 #resolveGetterConflicts(Map<String, List<Method>> conflictingGetters)
類似贡翘。
(3)一個(gè)符合 JavaBean 規(guī)范的類應(yīng)該同時(shí)有 getter 和 setter,并且 getter 的返回類型和 setter 的參數(shù)類型一致砰逻;程序先去處理 getter鸣驱,所以這里先根據(jù)屬性名從 getTypes
獲取到 getter 的返回類型。
- (3.1)如果返回類型為空蝠咆,證明該屬性沒(méi)有 getter 方法踊东,這里拋出異常。
- (3.2)如果不為空刚操,則遍歷所有的 setter闸翅,找到參數(shù)個(gè)數(shù)為1并且參數(shù)類型與 getter 返回類型相同的方法,找到即賦值給變量
setter
菊霜,并跳出循環(huán)坚冀。
(4)如果沒(méi)找到符合規(guī)范的 setter 方法,則拋出異常鉴逞。
(5)調(diào)用#addSetMethod(String name, Method method)
方法真正填充setMethods
和setTypes
集合遗菠,其代碼很簡(jiǎn)單联喘,同樣跟上面的#addGetMethod(String name, Method method)
類似,源碼如下:
private void addSetMethod(String name, Method method) {
// 篩選過(guò)濾掉非法的屬性名
if (isValidPropertyName(name)) {
// 將屬性名以及對(duì)應(yīng)的MethodInvoker對(duì)象添加到setMethods集合中辙纬,MethodInvoker是對(duì)Method對(duì)象反射操作的封裝
setMethods.put(name, new MethodInvoker(method));
// 因?yàn)榉椒ǚ祷刂抵锌赡軒в蟹盒停琫g: List<T>
// 所以通過(guò)TypeParameterResolver.resolveReturnType()方法將類型信息解析到Type對(duì)象中
Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);
// 將屬性名稱和對(duì)應(yīng)的返回值類型添加到setTypes集合中保存
setTypes.put(name, typeToClass(paramTypes[0]));
}
}
9叭喜、addFields(Class<?> clazz)
【功能】對(duì)于沒(méi)有 getter 和 setter 的屬性贺拣,通過(guò)本方法處理,填充到 getMethods
捂蕴、getTypes
譬涡、setMethods
、setTypes
集合中啥辨,在獲取設(shè)置這些屬性值時(shí)涡匀,是通過(guò) Field
對(duì)象的反射方法 get
、set
實(shí)現(xiàn)的溉知,是對(duì) #addSetMethods(...)
和 #addGetMethods(...)
方法的補(bǔ)充陨瘩。
【源碼與注解】
private void addFields(Class<?> clazz) {
// (1)獲取類中聲明的所有field屬性,包含了已經(jīng)解析出來(lái)的有 getter&setter 的屬性
Field[] fields = clazz.getDeclaredFields();
// 遍歷field屬性
for (Field field : fields) {
// 設(shè)置私有屬性訪問(wèn)權(quán)限
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
// (2)過(guò)濾掉已經(jīng)有 getter 和 setter 的屬性
if (!setMethods.containsKey(field.getName())) {
// (2.1)獲取類的修飾符级乍,過(guò)濾掉被聲明為static final的屬性舌劳,這些屬性只能被類加載器設(shè)置其初始值
int modifiers = field.getModifiers();
if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
// (2.2)
addSetField(field);
}
}
if (!getMethods.containsKey(field.getName())) {
// (2.3)
addGetField(field);
}
}
}
// (3)獲取父類,找出父類中聲明的屬性
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
【詳解】
(1)獲取類中聲明的所有field屬性玫荣,包含了已經(jīng)解析出來(lái)的有 getter&setter 的屬性甚淡。
(2)過(guò)濾掉已經(jīng)有 getter&setter 的屬性。
- (2.1)過(guò)濾掉被聲明為
static final
的屬性捅厂,這類屬性只允許被類加載器初始化贯卦。 - (2.2)調(diào)用
#addSetField(Field field)
填充setMethods
和setTypes
集合,源碼如下:
private void addSetField(Field field) {
// 過(guò)濾掉非法的屬性
if (isValidPropertyName(field.getName())) {
// 創(chuàng)建封裝了屬性對(duì)應(yīng)Field對(duì)象的SetFieldInvoker對(duì)象焙贷,內(nèi)部利用Field的set方法來(lái)反射設(shè)置屬性值
setMethods.put(field.getName(), new SetFieldInvoker(field));
// 解析獲取屬性值的具體類型(如果帶泛型或通配符)
Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
// 將屬性和屬性值類型對(duì)應(yīng)的Class對(duì)象映射填充setTypes集合
setTypes.put(field.getName(), typeToClass(fieldType));
}
}
- (2.3)調(diào)用
#addGetField(Field field)
填充getMethods
和getTypes
集合撵割,源碼如下:
private void addGetField(Field field) {
// 過(guò)濾掉非法的屬性
if (isValidPropertyName(field.getName())) {
// 創(chuàng)建封裝了屬性對(duì)應(yīng)Field對(duì)象的GetFieldInvoker對(duì)象,內(nèi)部利用Field的get方法來(lái)反射設(shè)置屬性值
getMethods.put(field.getName(), new GetFieldInvoker(field));
// 解析獲取屬性值的具體類型(如果帶泛型或通配符)
Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
// 將屬性和屬性值類型對(duì)應(yīng)的Class對(duì)象映射填充setTypes集合
getTypes.put(field.getName(), typeToClass(fieldType));
}
}
(3)獲取父類盈厘,通過(guò)遞歸調(diào)用本方法找出父類中聲明的屬性睁枕。
10、其他方法
【功能】主要是對(duì) Reflector
類中的屬性的使用沸手,對(duì)外暴露使用的方法外遇。
- (1)
#hasDefaultConstructor()
:判斷被解析的類是否有構(gòu)造方法。 - (2)
#getSetInvoker(String propertyName)
:根據(jù)屬性名獲取對(duì)應(yīng)的 Invoker 對(duì)象契吉,可通過(guò)該對(duì)象設(shè)置屬性值跳仿。 - (3)
#getGetInvoker(String propertyName)
:根據(jù)屬性名獲取對(duì)應(yīng)的 Invoker 對(duì)象,可通過(guò)該對(duì)象獲取屬性值捐晶。 - (4)
#getSetterType(String propertyName)
:根據(jù)屬性名獲取對(duì)應(yīng)的 setter 方法的參數(shù)類型對(duì)應(yīng)的 Class 對(duì)象菲语。 - (5)
#getGetterType(String propertyName)
:根據(jù)屬性名獲取對(duì)應(yīng)的 getter 方法的返回值類型對(duì)應(yīng)的 Class 對(duì)象妄辩。 - (6)
#getGetablePropertyNames()
:獲取類的所有可讀屬性。 - (7)
#getSetablePropertyNames()
:獲取類的所有可寫(xiě)屬性山上。 - (8)
#hasSetter(String propertyName)
:判斷傳入的屬性名是否有 setter眼耀,可用來(lái)判斷被解析的類是否有某屬性或是否可設(shè)置某屬性。 - (9)
#hasGetter(String propertyName)
:判斷傳入的屬性名是否有 getter佩憾,可用來(lái)判斷被解析的類是否有某屬性或是否可讀取某屬性哮伟。 - (10)
#findPropertyName(String name)
:根據(jù)傳入不區(qū)分大小寫(xiě)的屬性名獲取實(shí)際真實(shí)的屬性名。
五妄帘、ReflectorFactory
??ReflectorFactory
是一個(gè)接口楞黄,定義了創(chuàng)建和緩存 Reflector 對(duì)象的方法,只有一個(gè)實(shí)現(xiàn)類 DefaultReflectorFactory
抡驼,類關(guān)系圖如下:
??
ReflectorFactory
接口定義如下:
public interface ReflectorFactory {
// 判斷和設(shè)置是否有緩存Reflector對(duì)象
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean classCacheEnabled);
// 根據(jù)傳入的Class對(duì)象鬼廓,創(chuàng)建對(duì)應(yīng)的Reflector對(duì)象
Reflector findForClass(Class<?> type);
}
【解析】
??#isClassCacheEnabled()
、#setClassCacheEnabled()
方法提供了調(diào)用代碼Reflector工廠對(duì)象是否有緩存生成的 Reflector 對(duì)象的信息致盟,#findForClass(Class<?> type)
方法則是根據(jù)傳入的 Class 對(duì)象創(chuàng)建 Reflector 對(duì)象碎税。
??唯一一個(gè)實(shí)現(xiàn)類 DefaultReflectorFactory
的源碼如下:
public class DefaultReflectorFactory implements ReflectorFactory {
// 判斷是否要緩存Reflector對(duì)象的標(biāo)志位
private boolean classCacheEnabled = true;
// Reflector對(duì)象緩存
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();
public DefaultReflectorFactory() {
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
@Override
public Reflector findForClass(Class<?> type) {
// 如果有緩存,則先嘗試從緩存中取勾邦,如果緩存中沒(méi)有則先創(chuàng)建Reflector對(duì)象蚣录,再放入緩存,最后返回
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
Reflector cached = reflectorMap.get(type);
if (cached == null) {
cached = new Reflector(type);
reflectorMap.put(type, cached);
}
return cached;
} else {
// 如果沒(méi)有緩存眷篇,直接創(chuàng)建Reflector對(duì)象即可
return new Reflector(type);
}
}
}
【解析】
??代碼比較簡(jiǎn)單萎河,通過(guò)一個(gè)布爾型的標(biāo)志位 classCacheEnabled
判斷是否要對(duì)生成的 Reflector 對(duì)象進(jìn)行緩存,前兩個(gè)接口方法的實(shí)現(xiàn)也依賴于這個(gè)標(biāo)志位蕉饼;定義了一個(gè)并發(fā)容器 reflectorMap
緩存 Class 對(duì)象及 Reflector 對(duì)象的映射關(guān)系虐杯,將并發(fā)控制委托給 ConcurrentMap,#findForClass()
方法中昧港,如果有緩存擎椰,先從緩存中取,如果不為空直接返回创肥,如果為空則先創(chuàng)建再緩存最后返回达舒,如果沒(méi)緩存,則每次都直接創(chuàng)建返回叹侄。
六巩搏、測(cè)試案例
??先來(lái)個(gè)簡(jiǎn)單的,不帶繼承關(guān)系趾代,不帶泛型的JavaBean贯底,如下:
public class ReflectorTest {
// 簡(jiǎn)單Java類
static class SimpleJavaBean {
private Long id;
private String username;
private double money;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "{ id:" + id + ", username:" + username + ", money:" + money + " }";
}
}
}
??測(cè)試案例覆蓋了 Reflector
對(duì)外暴露的所有方法,單元測(cè)試代碼如下:
@Test
public void testSimpleJavaBean() throws InvocationTargetException, IllegalAccessException {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(SimpleJavaBean.class);
Assert.assertTrue(reflector.hasDefaultConstructor());
String[] readablePropertyNames = reflector.getGetablePropertyNames();
Assert.assertEquals(3, readablePropertyNames.length);
// 輸出 money id username撒强,雖然money沒(méi)有顯式的getter禽捆,但是可以通過(guò)反射獲取笙什,所以也是可讀屬性
System.out.println("[readablePropertyNames] ");
for (String name : readablePropertyNames)
System.out.print(name + " ");
System.out.println();
String[] writeablePropertyNames = reflector.getSetablePropertyNames();
Assert.assertEquals(3, writeablePropertyNames.length);
System.out.println("[writeablePropertyNames]");
for (String name : writeablePropertyNames)
System.out.print(name + " ");
System.out.println();
Assert.assertEquals(Long.class, reflector.getGetterType("id"));
Assert.assertEquals(String.class, reflector.getSetterType("username"));
Assert.assertEquals(double.class, reflector.getGetterType("money"));
Assert.assertTrue(reflector.hasGetter("id"));
Assert.assertTrue(reflector.hasSetter("money"));
Assert.assertEquals("id", reflector.findPropertyName("ID"));
Assert.assertEquals("username", reflector.findPropertyName("Username"));
SimpleJavaBean bean = new SimpleJavaBean();
System.out.println("bean(before call Invoker): " + bean);
Invoker idSetInvoker = reflector.getSetInvoker("id");
idSetInvoker.invoke(bean, new Object[]{100L});
Invoker idGetInvoker = reflector.getGetInvoker("id");
Assert.assertEquals(100L, idGetInvoker.invoke(bean, new Object[] {}));
Invoker usernameSetInvoker = reflector.getSetInvoker("username");
usernameSetInvoker.invoke(bean, new Object[]{"zhangsan"});
Invoker moneySetInvoker = reflector.getSetInvoker("money");
moneySetInvoker.invoke(bean, new Object[]{2.33});
System.out.println("bean(after call Invoker): " + bean);
}
??執(zhí)行結(jié)果如下:
??復(fù)雜一點(diǎn),經(jīng)過(guò)上面的源碼分析可知胚想,解析類屬性時(shí)不僅會(huì)解析類中定義的琐凭,還會(huì)通過(guò)解析接口和父類獲取 getter/setter 方法,最后解析出屬性名和屬性類型顿仇,所以定義一個(gè)測(cè)試接口和實(shí)現(xiàn)了接口的抽象父類淘正,最后被測(cè)試的類繼承了抽象父類,代碼如下:
// 接口定義
static interface Entity<T> {
T getId();
void setId(T id);
}
// 抽象父類實(shí)現(xiàn)了接口
static abstract class AbstractEntity implements Entity<Long> {
private Long id;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
}
// 類繼承了父類臼闻,間接實(shí)現(xiàn)了接口
static class Section extends AbstractEntity {
}
??測(cè)試代碼聚焦是否能獲取到繼承的屬性和正確解析類型,如下:
@Test
public void testGetSetterType() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assert.assertEquals(Long.class, reflector.getSetterType("id"));
}
@Test
public void testGetGetterType() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assert.assertEquals(Long.class, reflector.getGetterType("id"));
}
@Test
public void shouldNotGetClass() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assert.assertFalse(reflector.hasGetter("class"));
}
??執(zhí)行結(jié)果:
??更復(fù)雜一些囤采,屬性的類型可能是比較復(fù)雜的類型述呐,比如鏈表List、數(shù)組蕉毯,屬性可能是私有的乓搬,一般帶泛型的類是設(shè)計(jì)用來(lái)復(fù)用的,其中子類繼承帶泛型的父類并且指定類型是一種常用的形式代虾,所以類定義如下:
static abstract class Parent<T extends Serializable> {
protected T id;
protected List<T> list;
protected T[] array;
private T fld;
public T pubFld;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public T[] getArray() {
return array;
}
public void setArray(T[] array) {
this.array = array;
}
public T getFld() {
return fld;
}
}
static class Child extends Parent<String> {
}
??測(cè)試代碼如下:
// 測(cè)試是否能解析出泛型
@Test
public void shouldResolveSetterParam() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(String.class, reflector.getSetterType("id"));
}
// 測(cè)試解析復(fù)雜的類型鏈表
@Test
public void shouldResolveParameterizedSetterParam() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(List.class, reflector.getSetterType("list"));
}
// 測(cè)試解析復(fù)雜的類型數(shù)組
@Test
public void shouldResolveArraySetterParam() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
Class<?> clazz = reflector.getSetterType("array");
assertTrue(clazz.isArray());
assertEquals(String.class, clazz.getComponentType());
}
@Test
public void shouldResolveGetterType() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(String.class, reflector.getGetterType("id"));
}
@Test
public void shouldResolveSetterTypeFromPrivateField() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(String.class, reflector.getSetterType("fld"));
}
@Test
public void shouldResolveGetterTypeFromPublicField() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(String.class, reflector.getGetterType("pubFld"));
}
@Test
public void shouldResolveParameterizedGetterType() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
assertEquals(List.class, reflector.getGetterType("list"));
}
@Test
public void shouldResolveArrayGetterType() throws Exception {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Child.class);
Class<?> clazz = reflector.getGetterType("array");
assertTrue(clazz.isArray());
assertEquals(String.class, clazz.getComponentType());
}
??執(zhí)行結(jié)果:
??通過(guò)上面幾個(gè)測(cè)試案例进肯,可以比較好地學(xué)習(xí)掌握
Reflector
的用法。