Java之reflection(反射機制)——經過反射操做泛型,註解

1、反射操做泛型(Generic)


  Java採用泛型擦除機制來引入泛型。Java中的泛型僅僅是給編譯器Javac使用的,確保數據的安全性和免去強制類型轉換的麻煩。可是編譯一旦完成,全部和泛型有關的類型所有被擦除。 
  爲了經過反射操做這些類型以迎合實際開發的須要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種類型來表明不能被歸一到Class類中的類型可是又和原始類型齊名的類型。 
  java

  • ParameterizedType:表示一種參數化的類型,好比Collection< String >
  • GenericArrayType:表示一種元素類型是參數化類型或者類型變量的數組類型
  • TypeVariable:是各類類型變量的公共父接口
  • 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性能

2、反射操做註解(Annotation)

Method/Constructor/Field/Element 都繼承了 AccessibleObject , AccessibleObject 類中有一個 setAccessible 方法:測試


具體使用能夠就看個人以前的文章 註解處理器spa

好了,介紹了兩個簡單的反射的應用,在順便講一下Java反射機制的性能問題。.net

3、反射性能測試

Method/Constructor/Field/Element 都繼承了 AccessibleObject , AccessibleObject 類中有一個 setAccessible 方法:code

public void setAccessible(booleanflag)throws SecurityException { ... }

該方法有兩個做用:對象

  1. 啓用/禁用訪問安全檢查開關:值爲true,則指示反射的對象在使用時取消Java語言訪問檢查; 值爲false,則指示應該實施Java語言的訪問檢查;
  2. 能夠禁止安全檢查, 提升反射的運行效率.

測試代碼

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+次(並且服務器的性能也確定比個人機器要高),所以在咱們的實際開發中,實際上是不用擔憂反射機制帶來的性能消耗的,並且禁用訪問權限檢查,也會有性能的提高。

相關文章
相關標籤/搜索