Android註解、反射、泛型的學習記錄

註解:
       Annotation其實就是代碼裏的特殊標記, 它用於替代配置文件,也就是說,傳統方式通過配置文件告訴類如何運行,有了註解技術後,開發人員可以通過註解告訴類如何運行,註解本身對程序運行不會發生什麼變化,而通過反射取得註解的對象進行處理纔會對程序發生變化。

註解的一些意義:
      1、系統的一些註解,如@override @NoNull 是爲了更好的給程序開發者更友好的提示。而無實際運行意義存在

      2、我們常常利用註解加反射的形式,來達到定位標誌來利用的作用,如@Login標誌註解Activity,來告訴程序這個Activity需要登錄,單純的註解無法達到效果,而是應該通過反射找到該類是否有@Login來對他進行登錄跳轉的處理。 

註解是以'@註解名'在代碼中存在的,根據註解參數的個數,我們可以將註解分爲:標記註解、單值註解、完整註解三類。它們都不會直接影響到程序的語義,只是作爲註解(標識)存在,我們可以通過反射機制編程實現對這些元數據(用來描述數據的數據)的訪問。有三個最基本的註解,@Override: 限定重寫父類方法, 該註解只能用於方法;@Deprecated: 用於表示某個程序元素(類, 方法等)已過時;@SuppressWarnings: 抑制編譯器警告。註解屬性的類型只能是如下類型:String類型、8大基本數據類型、Class類型、枚舉類型、註解類型以及以上類型的一維數組。有如果一個註解只有一個屬性,並且這個屬性的名稱爲value的話,那麼使用註解時可以省略value=部分,如@MyAnnotation(“xxx"),直接賦值。

元註解:
元註解也就是註解的註解,Java中提供了四種元註解,專門負責註解其他的註解,分別如下:
1.@Retention元註解,表示需要在什麼級別保存該註解信息(生命週期)。   如果註解類型聲明中不存在 Retention 註解,則保留策略默認爲 RetentionPolicy.CLASS。可選的  RetentionPoicy參數包括:
    RetentionPolicy.SOURCE: 停留在java源文件,編譯器被丟掉。
    RetentionPolicy.CLASS:停留在class文件中,但會被VM丟棄(默認)。
    RetentionPolicy.RUNTIME:內存中的字節碼,VM將在運行時也保留註解,因此可以通過反射機制讀取註解的信息。


2.@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。只有元註解類型直接用於註解時,Target 元註釋纔有效。如果元註解類型用作另一種註解類型的成員,則無效。註釋類型所適用的程序元素的種類。如果註釋類型聲明中不存在 Target 元註釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元註釋,則編譯器強制實施指定的使用限制。
   ElementType.CONSTRUCTOR: 構造器聲明
   ElementType.FIELD: 成員變量、對象、屬性(包括enum實例)
   ElementType.LOCAL_VARIABLE: 局部變量聲明
   ElementType.METHOD: 方法聲明
   ElementType.PACKAGE: 包聲明
   ElementType.PARAMETER: 參數聲明
   ElementType.TYPE: 類、接口(包括註解類型)或enum聲明


3.@Documented將註解包含在JavaDoc中
某一類型的註釋將通過 javadoc 和類似的默認工具進行文檔化,應使用此類型來註釋這些類型的聲明,其註釋會影響由其客戶端註釋的元素的使用。如果類型聲明是用Documented 來註釋的,則其註釋將成爲註釋元素的公共 API 的一部分。


4.@Inheried允許子類繼承父類中的註解,註釋類型被自動繼承。

如果在註釋類型聲明中存在 Inherited 元註釋,並且用戶在某一類聲明中查詢該註釋類型,同時該類聲明中沒有此類型的註釋,則將在該類的超類中自動查詢該註釋類型。此過程會重複進行,直到找到此類型的註釋或到達了該類層次結構的頂層 (Object) 爲止。如果沒有超類具有該類型的註釋,則查詢將指示當前類沒有這樣的註釋。如果使用註釋類型註釋類以外的任何事物,此元註釋類型都是無效的。此元註釋僅促成從超類繼承註釋,對已實現接口的註釋無效。

反射:

什麼事反射?

在運行中,能動態的獲取或修改類或對象任何的屬性和方法的功能,這就是java中的反射。

利用反射機制在Java程序中,動態的去調用一些protected甚至是private的方法或類,這樣可以很大程度上滿足我們的一些比較特殊需求。在Java中的反射機制,被稱爲Reflection。它允許運行中的Java程序對自身進行檢查,並能直接操作程序的內部屬性或方法。Reflection機制允許程序在正在執行的過程中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,並可以在執行的過程中,動態生成Instances、變更fields內容或喚起methods。簡單的來說,反射機制就是允許編程人員在程序運行時來改變程序的結構或者變量的類型。通過這個特性,我們可以在運行時得知某個類的所有成員,包括其屬性和方法,同時也能夠調用這些方法。請注意反射機制的特殊之處就在於可以使用編譯期間完全未知的類,也就是通過反射機制可以加載一個在運行時才得知名字的類,從而取得其內部的成員函數並調用。

Class 表示某個具體的類或接口
Object 每個類都使用Object 做爲超類,所有對象都實現這個類的方法
Constructor 封裝了Class的構造方法
Field 提供有關類或接口的屬性信息,以及對它的動態訪問權限
Method 提供類或者接口上的方法的信息
Modifier 封裝了Class(method、fields)的修飾域

獲取類的相關信息

1.Class類提供了四個public方法,用於獲取某個類的構造方法。
Constructor getConstructor(Class[] params)根據構造函數的參數,返回一個具體的具有public屬性的構造函數
Constructor getConstructors()返回所有具有public屬性的構造函數數組
Constructor getDeclaredConstructor(Class[] params)根據構造函數的參數,返回一個具體的構造函數(不分public和非public屬性)
Constructor getDeclaredConstructors()返回該類中所有的構造函數數組(不分public和非public屬性)

 Class<? extends E>  clazz = me.getClass();
 String clazzName = clazz.getName();//獲取類名         
 //獲取構造函數
 //獲取某個確定的public構造函數,帶一個int參數
 Constructor<? extends E> constructor= clazz.getConstructor(int.class);
 //獲取某個確定的public構造函數,帶一個int參數
 Constructor<?>[]  constructors = clazz.getConstructors();
 //獲取某個確定的public或非public構造函數,帶一個int參數
 Constructor<? extends E>  constructorm = clazz.getDeclaredConstructor(int.class);
 //獲取某個確定的public或非public構造函數,帶一個int參數
 Constructor<?>[] constructorsm = clazz.getDeclaredConstructors();

2.與獲取構造方法的方式相同,存在四種獲取成員方法的方式。
Method getMethod(String name, Class[] params)根據方法名和參數,返回一個具體的具有public屬性的方法
Method[] getMethods()返回所有具有public屬性的方法數組
Method getDeclaredMethod(String name, Class[] params)根據方法名和參數,返回一個具體的方法(不分public和非public屬性)
Method[] getDeclaredMethods()返回該類中的所有的方法數組(不分public和非public屬性)
說明:方法getDeclaredMethods()只能獲取到由當前類定義的所有方法,不能獲取從父類繼承的方法。
方法getMethods() 不僅能獲取到當前類定義的public方法,也能得到從父類繼承和已經實現接口的public方法。

 //獲取方法
 //獲取public的方法 方法名  和方法參數
 Method method = clazz.getMethod("name", String.class);
 //獲取public的所有方法
 Method[] methods = clazz.getMethods();
 //獲取public或非public的方法 方法名  和方法參數
 Method methodm = clazz.getDeclaredMethod("name", String.class);
 //獲取public或非public的所有方法
 Method[] methodsm = clazz.getDeclaredMethods();
 
 //獲取方法名
 method.getName();
 //獲取方法的修飾符、這裏獲取到的修飾符需要轉換的
 int modifiers = method.getModifiers();
 String strModifiers = Modifier.toString(modifiers);         
 //獲取方法的返回類型
 String returnType = method.getReturnType().getName();
 //獲取方法的參數列表
 Class<?>[] parameterTypes = method.getParameterTypes();
 parameterTypes[0].getName();

3.存在四種獲取成員屬性的方法
Field getField(String name)根據變量名,返回一個具體的具有public屬性的成員變量
Field[] getFields()返回具有public屬性的成員變量的數組
Field getDeclaredField(String name)根據變量名,返回一個成員變量(不分public和非public屬性)
Field[] getDelcaredField()返回所有成員變量組成的數組(不分public和非public屬性)
 //獲取成員變量
 Field field = clazz.getField("i");
 clazz.getFields();
 clazz.getDeclaredField("i");
 clazz.getDeclaredFields();
 //屬性類型
 field.getType();
 //屬性修飾符
 field.getModifiers();
 //屬性名
 String fieldName = field.getName();
 Field fieldm = clazz.getField(fieldName);
 //設置私有屬性可以訪問
 fieldm.setAccessible(true);
 //屬性值
 Object fieldValue = fieldm.get(me);
 //
 if (fieldValue != null) {
    String fieldValuem= fieldValue.toString();
     Log.d("", ""+fieldValuem);
}

4.獲取類、屬性、方法的修飾域
類Class、Method、Constructor、Field都有一個public方法int getModifiers()。該方法返回一個int類型的數,表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。Modifier類中定義了若干特定的修飾域,每個修飾域都是一個固定的int數值,列表如下:


該類不僅提供了若干用於判斷是否擁有某中修飾域的方法boolean isXXXXX(int modifiers),還提供一個String toString(int modifier)方法,用於將一個表示修飾域組合值的int數轉換成描述修飾域的字符串。

 //獲取方法的修飾符、這裏獲取到的修飾符需要轉換的
 int modifiers = method.getModifiers();
 String strModifiers = Modifier.toString(modifiers);

代碼學習

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
 
public class LoadMethod {
 
    /**
     * 在運行時加載指定的類,並調用指定的方法
     * @param cName            Java的類名
     * @param MethodName       方法名
     * @param types            方法的參數類型
     * @param params        方法的參數值
     * @return
     */
    public Object Load(String cName, String MethodName, String[] types, String[] params) {       
        Object retObject = null;
        try {
            // 加載指定的類
            Class<?> clazz = Class.forName(cName);          
            // 利用newInstance()方法,獲取構造方法的實例
            // Class的newInstance方法只提供默認無參構造實例
            // Constructor的newInstance方法提供帶參的構造實例
            Constructor<?> constructor = clazz.getConstructor();
            Object obj = constructor.newInstance();    
            //如果是無參數的構造函數創建實例,用這個方法簡單一些
            //Object obj = clazz.newInstance();           
            //方法的參數類型
            Class<?> paramTypes[] = this.getMethodTypesClass(types);
            // 在指定類中獲取指定的方法
            Method meth = clazz.getMethod(MethodName, paramTypes);            
            //方法的參數值
            Object argList[] = this.getMethodParamObject(types, params);
            //調用指定的方法並獲取返回值爲Object類型
            retObject = meth.invoke(obj, argList);           
        } catch (Exception e) {
            System.err.println(e);
        }        
        return retObject;
    }
    
    /***獲取參數類型,返回值保存在Class[]中*/
    private Class<?>[] getMethodTypesClass(String[] types) {
        Class<?>[] cs = new Class[types.length];
        for (int i = 0; i < cs.length; i++) {
            if (types[i] != null || !types[i].trim().equals("")) {
                if (types[i].equals("int") || types[i].equals("Integer")) {
                    cs[i] = Integer.TYPE;
                } 
                else if (types[i].equals("float") || types[i].equals("Float")) {
                    cs[i] = Float.TYPE;
                }
                else if (types[i].equals("double") || types[i].equals("Double")) {
                    cs[i] = Double.TYPE;
                }
                else if (types[i].equals("boolean") || types[i].equals("Boolean")) {
                    cs[i] = Boolean.TYPE;
                }
                else {
                    cs[i] = String.class;
                }
            }
        }
        return cs;
    }
    
    /***獲取參數Object[]*/
    private Object[] getMethodParamObject(String[] types, String[] params) {
        Object[] retObjects = new Object[params.length];
        for (int i = 0; i < retObjects.length; i++) {
            if(!params[i].trim().equals("")||params[i]!=null){  
                if(types[i].equals("int")||types[i].equals("Integer")){  
                    retObjects[i] = Integer.valueOf(params[i]);
                }
                else if(types[i].equals("float")||types[i].equals("Float")){  
                    retObjects[i]= Float.valueOf(params[i]);
                }
                else if(types[i].equals("double")||types[i].equals("Double")){  
                    retObjects[i]= Double.valueOf(params[i]);  
                }
                else if(types[i].equals("boolean")||types[i].equals("Boolean")){  
                    retObjects[i]= Boolean.valueOf(params[i]); 
                }
                else{  
                    retObjects[i] = params[i];  
                }  
            } 
        }       
        return retObjects;
    } 
}

 

三、泛型

     1、什麼是泛型:

     泛型就是一個種通用的類型,在使用泛型的類型的類或方法中,不指定它是哪一種特定的類型,只有在使用的時候才知道他是哪種特定類型。

    2、泛型通配符

     ? 通配符類型 無邊界的通配符(Unbounded Wildcards), 就是<?>, 比如List<?>
       無邊界的通配符的主要作用就是讓泛型能夠接受未知類型的數據. 
        <? extends T> 表示類型的上界,表示參數化類型的可能是T 或是 T的子類
        <? super T> 表示類型下界(Java Core中叫超類型限定),
        表示參數化類型是此類型的超類型(父類型),直至Object
        注意: 你可以爲一個泛型指定上邊界或下邊界, 但是不能同時指定上下邊界.



原文鏈接:https://blog.csdn.net/pcaxb/article/details/46646345

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章