反射是java語言中的一個(gè)特性焰宣,反射機(jī)制是指在程序的運(yùn)行狀態(tài)中,可以構(gòu)造任意一個(gè)類的對象谭溉,可以了解任意一個(gè)對象所屬的類墙懂,可以了解任意一個(gè)類的成員變量和方法,可以調(diào)用任意一個(gè)對象的屬性和方法扮念。 這種動(dòng)態(tài)獲取程序信息以及動(dòng)態(tài)調(diào)用對象的功能稱為Java語言的反射機(jī)制损搬。 反射被視為動(dòng)態(tài)語言的關(guān)鍵。
以上是java關(guān)于反射的八股文,可能不是很好背巧勤,但是絕大部分java程序員都不會(huì)在實(shí)際開發(fā)中去使用反射嵌灰。
合理使用反射,可以讓代碼再不影響性能的基礎(chǔ)上更加優(yōu)美颅悉,拓展性更加的好沽瞭。
下面從幾個(gè)點(diǎn)來講解反射的使用
反射的一些問題
使用反射一定性能差?
很多程序員可能
都會(huì)以反射性能不好的原因去拒絕使用反射剩瓶。想要合理(風(fēng)騷)的使用反射驹溃,首先需要了解反射為什么性能不好。反射的性能問題總體來說有三點(diǎn)
1.反射調(diào)用過程中會(huì)產(chǎn)生大量的臨時(shí)對象儒搭,這些對象會(huì)消耗內(nèi)存,增加gc頻率芙贫,從而影響性能搂鲫。
2.反射調(diào)用方法時(shí)會(huì)從方法數(shù)組中遍歷查找,并且會(huì)檢查可見性等操作會(huì)耗時(shí)磺平。
3.反射在達(dá)到一定次數(shù)時(shí)魂仍,會(huì)動(dòng)態(tài)編寫字節(jié)碼并加載到內(nèi)存中,這個(gè)字節(jié)碼沒有經(jīng)過編譯器優(yōu)化拣挪,也不能享受JIT優(yōu)化擦酌。
那么如何去優(yōu)化:
1.如果是使用反射去讀取字段,讀取方法菠劝,可以使用一個(gè)公共類在初始化的時(shí)候掃描運(yùn)行過程中可能需要使用的反射的類赊舶,并緩存反射后的一些結(jié)果,如Field,Methord方法赶诊。
2.不在超高并發(fā)的請求鏈路中使用反射中的invoke,field的set,get等操作笼平,因?yàn)椴荒芟硎躂IT優(yōu)化,不過問題不大舔痪,實(shí)際測試寓调,影響其實(shí)很小(只要使用地方不太多锄码,是可以使用的)夺英。
總結(jié)一下就是,只需要合理設(shè)置緩存滋捶,考慮性能問題痛悯,在任何地方使用反射都沒啥大問題,你的編程的思想才是限制你程序性能的最主要的因素重窟。
反射能做什么灸蟆?
1. 獲取當(dāng)前的類的class信息
Class my = this.getClass();
System.out.println("我是誰"+my.getName());
System.out.println("我有哪些成員變量"+ Arrays.toString(my.getDeclaredFields()));
System.out.println("我有哪些成員變量(包含私有,但不包括繼承的)"+ Arrays.toString(my.getDeclaredFields()));
System.out.println("我有哪些方法"+ Arrays.toString(my.getMethods()));
System.out.println("我有哪些方法(包含私有,但不包括繼承的方法)"+ Arrays.toString(my.getDeclaredMethods()));
System.out.println("我有哪些注解(包含繼承)"+ Arrays.toString(my.getAnnotations()));
System.out.println("我有哪些注解(不包含繼承)"+ Arrays.toString(my.getDeclaredAnnotations()));
這樣一來,就獲取了當(dāng)前類的class對象,并獲得了成員變量炒考,方法可缚,注解一系列的信息。
2.對成員變量進(jìn)行操作
Field fieldOne = this.getClass().getDeclaredField("dateList");
System.out.println("字段是什么類型斋枢?"+fieldOne.getType());
//這個(gè)字段是不是Collection接口的實(shí)現(xiàn)類帘靡?
if (Collection.class.isAssignableFrom(fieldOne.getType())
&& fieldOne.getGenericType() instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) fieldOne.getGenericType();
Type[] fieldArgTypes = parameterizedType.getActualTypeArguments();
for (Type fieldArgType : fieldArgTypes) {
System.out.println("集合類型是什么類型的集合?"+(Class) fieldArgType);
}
}
//給這個(gè)字段賦值瓤帚,注意:類型需要兼容侵蒙,可以是子類
fieldOne.set(this, Lists.newArrayList("123123","1212"));
System.out.println("通過反射后設(shè)置進(jìn)去了什么值,通過反射獲取出來看看"+fieldOne.get(this));
通過getType可以直接拿到class飘千,并且通過getGenericType返回的ParameterizedType中的ActualTypeArguments可以獲取到字段類型<T>中的類型class隘世。也可以直接調(diào)用set/get獲取字段的值或者是設(shè)置字段的值
3.對方法進(jìn)行操作
拿到了xxx.class對象的時(shí)候,直接調(diào)用getMethod或者getMethods方法就可以怯邪,可以拿到方法的Method對象绊寻。這里,如果是常用方法悬秉,可以把這個(gè)對象緩存起來澄步。Method最常用的方法是method.invoke(),通過傳入對象本身和方法對應(yīng)的入?yún)⒑兔冢{(diào)用方法村缸。此外,如果是私有方法武氓,可以使用method.setAccessible(true)取消權(quán)限檢查
Method testMethod = my.getMethod("test",String.class,Integer.class);
testMethod.setAccessible(true);
String result = (String)testMethod.invoke(my,"haha", 1);
System.out.println(result);
4.對抽象父類的泛型獲取子類的具體填充類型梯皿。
開發(fā)的時(shí)候有時(shí)候父類形如 XXX<T>的,需要在父類定義一些通用的方法县恕,但是這時(shí)候需要?jiǎng)?chuàng)建一個(gè)T類型的示例索烹,這時(shí)候因?yàn)閖ava擦除的特效,T的屬性是被擦除的弱睦,需要如何去獲得T的類型呢百姓。
利用反射原理,子類的T如果已經(jīng)確定况木,調(diào)用父類的方法垒拢,是可以獲得當(dāng)前this對象的T的class或者是實(shí)例.
關(guān)鍵方法 getActualTypeArguments。這個(gè)方法可以獲得當(dāng)前泛型類型的數(shù)組火惊,作用在實(shí)例對象上求类。
private T createModel() {
try {
Type superClass = getClass().getGenericSuperclass();
//關(guān)鍵代碼,拿到當(dāng)前類<>中的第一個(gè)類型例如<K.V>屹耐,getActualTypeArguments的返回K下標(biāo)為0尸疆,V下標(biāo)為1
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Class<?> clazz = getRawType(type);
return (T) clazz.newInstance();
} catch (Exception e) {
log.error("AbstactYsConfig createModel error",e);
}
return null;
}
private static Class<?> getRawType(Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type rawType = parameterizedType.getRawType();
return (Class) rawType;
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
} else if (type instanceof TypeVariable) {
return Object.class;
} else if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);
} else {
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <" + type + "> is of type " + className);
}
}