Java採用泛型擦除機制來引入泛型。Java中的泛型僅僅是給編譯器Javac使用的,確保數據的安全性和免去強制類型轉換的麻煩。可是編譯一旦完成,全部和泛型有關的類型所有被擦除。
爲了經過反射操做這些類型以迎合實際開發的須要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種類型來表明不能被歸一到Class類中的類型可是又和原始類型齊名的類型。
java
WildcardType:表明一種通配符類型表達式,好比?、? extends Number、? super Integer。(wildcard是一個單詞:就是」通配符「)數組
代碼示例:安全
package reflection; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; /** * 經過反射獲取泛型信息 * */ public class Demo{ //定義兩個帶泛型的方法 public void test01(Map<String,Person> map,List<Person> list){ System.out.println("Demo.test01()"); } public Map<Integer,Person> test02(){ System.out.println("Demo.test02()"); return null; } public static void main(String[] args) { try { //得到指定方法參數泛型信息 Method m = Demo.class.getMethod("test01", Map.class,List.class); Type[] t = m.getGenericParameterTypes(); for (Type paramType : t) { System.out.println("#"+paramType); if(paramType instanceof ParameterizedType){ //獲取泛型中的具體信息 Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments(); for (Type genericType : genericTypes) { System.out.println("泛型類型:"+genericType); } } } //得到指定方法返回值泛型信息 Method m2 = Demo.class.getMethod("test02", null); Type returnType = m2.getGenericReturnType(); if(returnType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments(); for (Type genericType : genericTypes) { System.out.println("返回值,泛型類型:"+genericType); } } } catch (Exception e) { e.printStackTrace(); } } }
輸出結果:
#java.util.Map< java.lang.String, reflection.Person >
泛型類型:class java.lang.String
泛型類型:class reflection.Person
#java.util.List< reflection.Person >
泛型類型:class reflection.Person服務器
返回值,泛型類型:class java.lang.Integer
返回值,泛型類型:class reflection.Person性能
Method/Constructor/Field/Element 都繼承了 AccessibleObject , AccessibleObject 類中有一個 setAccessible 方法:測試
具體使用能夠就看個人以前的文章 註解處理器spa
好了,介紹了兩個簡單的反射的應用,在順便講一下Java反射機制的性能問題。.net
Method/Constructor/Field/Element 都繼承了 AccessibleObject , AccessibleObject 類中有一個 setAccessible 方法:code
public void setAccessible(booleanflag)throws SecurityException { ... }
該方法有兩個做用:對象
測試代碼:
package reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestReflect { public static void testNoneReflect() { Person user = new Person(); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { user.getName(); } long count = System.currentTimeMillis() - start; System.out.println("沒有反射, 共消耗 <" + count + "> 毫秒"); } public static void testNotAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Person user = new Person(); Method method = Class.forName("reflection.Person").getMethod("getName"); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { method.invoke(user, null); } long count = System.currentTimeMillis() - start; System.out.println("沒有訪問權限, 共消耗 <" + count + "> 毫秒"); } public static void testUseAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Person user = new Person(); Method method = Class.forName("reflection.Person").getMethod("getName"); method.setAccessible(true); long start = System.currentTimeMillis(); for (long i = 0; i < Integer.MAX_VALUE; ++i) { method.invoke(user, null); } long count = System.currentTimeMillis() - start; System.out.println("有訪問權限, 共消耗 <" + count + "> 毫秒"); } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { testNoneReflect(); testNotAccess(); testUseAccess(); } }
輸出結果:
沒有反射, 共消耗 <912> 毫秒
沒有訪問權限, 共消耗 <4366> 毫秒 有訪問權限, 共消耗 <2843> 毫秒
能夠看到使用反射會比直接調用慢2000 毫秒 ,可是前提是該方法會執行20E+次(並且服務器的性能也確定比個人機器要高),所以在咱們的實際開發中,實際上是不用擔憂反射機制帶來的性能消耗的,並且禁用訪問權限檢查,也會有性能的提高。