Java獲取未知類型對象的屬性


獲取未知類型對象的屬性通常有兩種方式:

一是通過自定義注解的方式,通過獲取被注解的屬性從而獲取屬性的值,這種方式也是Spring參數注入的重要實現手段

二是通過反射獲取屬性的名稱,通過屬性名從而獲取屬性,這種方式在開發時是比較簡便易實現的。

一、關於注解

1、自定義注解

    首先定義一個@interface類型的注解接口

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassBeanId {
}

     元注解的作用就是負責注解其他注解。
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited     這些類型和它們所支持的類在java.lang.annotation包中可以找到。下面我們看一下每個元注解的作用和相應分參數的使用說明。


    @Target說明了Annotation所修飾的對象范圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
    作用:用於描述注解的使用范圍(即:被描述的注解可以用在什么地方)
    取值(ElementType)有:
    1.CONSTRUCTOR:用於描述構造器
    2.FIELD:用於描述域
    3.LOCAL_VARIABLE:用於描述局部變量
    4.METHOD:用於描述方法
    5.PACKAGE:用於描述包
    6.PARAMETER:用於描述參數
    7.TYPE:用於描述類、接口(包括注解類型) 或enum聲明

    @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。
    作用:表示需要在什么級別保存該注釋信息,用於描述注解的生命周期(即:被描述的注解在什么范圍內有效)
    取值(RetentionPoicy)有:
    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在運行時有效(即運行時保留)
注:注解的的RetentionPolicy的屬性值是RUTIME,這樣注解處理器可以通過反射,獲取到該注解的屬性值,從而去做一些運行時的邏輯處理

Annotation類型里面的參數該怎么設定:
    第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這里把方法設為defaul默認類型; 
    第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這里的參數成員就為String;
    第三,如果只有一個參數成員,最好把參數名稱設為"value",后加小括號。

例如:

示例1:

自定義一個注解:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassBeanId {
    public int id() default -1;

}

 

使用這個注解:

public class ClassBean {
    @ClassBeanId(id = 20) //使用已定義的注解默認值為20。如果需要賦值,就需要用反射將id的值取出來並賦給當前類的id
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "ClassBean [id=" + id + "]";
    }
    
}

定義獲取該注解下的屬性

public static <T> void getData(T data) throws IllegalArgumentException, IllegalAccessException{
        int id = 0;
        Class clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            if(field.getAnnotation(ClassBeanId.class) != null){
                field.setAccessible(true);
                id = field.getInt(data);
            }
            System.out.println("id : "+id);
        }
    }

將對象傳入該方法中,通過反射判斷該對象屬性是否添加了注解,從而獲取該對象的id屬性。

若要實現類似Spring框架中的參數注入,則需要重新定義一組方法,將注解中的參數傳入對象之中,方法如下:

public static <T> void getDataFromAnnotation(T data) throws IllegalArgumentException, IllegalAccessException{
        int id = 0;
        Class clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            if(field.getAnnotation(ClassBeanId.class) != null){  //判斷該屬性是否被注解
                field.setAccessible(true);
                ClassBeanId classBeanId = field.getAnnotation(ClassBeanId.class); //實例該注解
                field.setInt(data, classBeanId.id());  //獲取注解的值並賦值給傳入對象
            }
        }
    }

雖然並非嚴格的Spring框架的實現機制,但是原理是相同的。

二、關於反射

通過反射獲取屬性的名稱,並對比屬性命名就可以獲取未知類型對象中某些屬性值。這是一種比較常見的做法。

public static <T> void getDataField(T data) throws IllegalArgumentException, IllegalAccessException{
        Class clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            String name = field.getName();
            if(name.equals("id")){
                field.setAccessible(true);
                field.setInt(data,29);
            }
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM