溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java開發(fā)反射機(jī)制實(shí)例代碼分析

發(fā)布時(shí)間:2022-05-17 11:25:43 來源:億速云 閱讀:131 作者:zzz 欄目:大數(shù)據(jù)

本文小編為大家詳細(xì)介紹“Java開發(fā)反射機(jī)制實(shí)例代碼分析”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Java開發(fā)反射機(jī)制實(shí)例代碼分析”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

前言

存在這樣一個(gè)類:

package com.example.demo;
import com.alibaba.fastjson.annotation.JSONField;
public class User {
    private String name;
    @Value( value ="age_a")
    private String age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

一、創(chuàng)建Class的三種方式

1 - Class clazz = Class.forName("com.example.demo.User");

Java開發(fā)反射機(jī)制實(shí)例代碼分析

注意一點(diǎn),這里的forName("xxx")的類名需要全名,且為接口或類,否則加載不了。

2 - User user = new User();

Class clazz2 = user.getClass();

Java開發(fā)反射機(jī)制實(shí)例代碼分析

3 - Class clazz3 = User.class;

以上三種方式,都可以獲取到類User的Class對象,通過Class,即可以開始玩反射了。

二、反射獲取類的所有屬性和屬性類型

Class clazz = User.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("屬性名:"+field.getName());
    System.out.println("屬性的類型:"+field.getGenericType().getTypeName());
}

打印輸出User的屬性和屬性類型——

屬性名:name

屬性的類型:java.lang.String

屬性名:age

屬性的類型:java.lang.String

利用反射獲取到類的字段屬性后,是不是可以利用反射來創(chuàng)建一個(gè)對象呢?答案是肯定的。

例如,可以類似下面代碼,通過反射得到的字段屬性,進(jìn)而創(chuàng)建一個(gè)對象。

Map<String,Object> fileds = new HashMap<>();
fileds.put("name","張三");
fileds.put("age","10");
Object o = User.class.newInstance();
 Field[] fields = o.getClass().getDeclaredFields();
 for (Field field : fields) {
     //設(shè)置后可用反射訪問訪問私有變量
     field.setAccessible(true);
     //通過反射給屬性賦值
     field.set(o,fileds.get(field.getName()));
 }
 User user1 = (User) o;
 System.out.println(user1.toString());

什么場景下可能需要這樣做的呢?像一些內(nèi)部數(shù)據(jù)與外部數(shù)據(jù)字段的映射,就可以通過類似的字段反射方式,將源數(shù)據(jù)映射給目標(biāo)數(shù)據(jù),進(jìn)而得到可以插入數(shù)據(jù)庫的目標(biāo)對象。

三、反射動(dòng)態(tài)修改類屬性的注解值

注意一點(diǎn),我們在設(shè)置User類時(shí),對其中一個(gè)字段加了注解:@Value( value ="age_a")。這是一種設(shè)置值的注解,既然是設(shè)置值,是否還可以在代碼運(yùn)行過程中,根據(jù)不同情況來動(dòng)態(tài)修改呢?

字段上的注解,其實(shí)都存放在一個(gè)memberValues屬性里,這是一個(gè)map,可以這樣來獲取——

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    //設(shè)置后可用反射訪問訪問私有變量
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
       //獲取 annotation 這個(gè)代理實(shí)例所持有的 InvocationHandler
       InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
       // 獲取 InvocationHandler 的 memberValues 字段
        Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
        memberValues.setAccessible(true);
        Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
        System.out.println(values);
    }
}

debug打斷點(diǎn),可以看到——

Java開發(fā)反射機(jī)制實(shí)例代碼分析

這個(gè)Map<String,Object>存儲(chǔ)的是該@注解里的所有屬性值,這里,@Value只有一個(gè)value屬性——

public @interface Value {
    String value();
}

若把它換成類似@JSONField(name="age_a"),把上邊的代碼稍微修改下,如:

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
          InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(JSONField.class));
  ......
    }
}

@JSONField注解的內(nèi)部屬性有如下方式——

Java開發(fā)反射機(jī)制實(shí)例代碼分析

再運(yùn)行剛剛的代碼,可以看到,這里Map<String,Object>獲取存儲(chǔ)到的,便是這個(gè)注解里所有的屬性與對應(yīng)的屬性值。

Java開發(fā)反射機(jī)制實(shí)例代碼分析

到了這一步,回到先前上邊的問題,若要?jiǎng)討B(tài)改變這個(gè)注解的值,怎么處理呢?

其實(shí),很簡單,只需要直接進(jìn)行值設(shè)置就可以了,例如——

InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
values.put("value","new_age");
memberValues.setAccessible(false);

只是,注意一點(diǎn)是,這里的key需要對應(yīng)上注解里是屬性值。

四、反射獲取類的方法及調(diào)用方式

 Object o=User.class.newInstance();
//通過反射獲取到User的setAge方法,后面的String.class表示這個(gè)setAge方法的參數(shù)類型,若有多個(gè),則按順序列出
//同時(shí),若為其他類型,如List,Long,則為List.class,Long.class
 Method m =  (Method) o.getClass().getMethod("setAge",String.class);
 m.invoke(o,"name");
 User user = (User) o;
 System.out.println(user);

打印可見,age已為name,說明setAge調(diào)用成功了。

Java開發(fā)反射機(jī)制實(shí)例代碼分析

這類使用場景,在代理當(dāng)中出現(xiàn)比較多。

最后,通過反射實(shí)現(xiàn)一個(gè)Map轉(zhuǎn)成對象的封裝工具——

   public Object MapToObject(Object object,Map<String, Object> map) throws IllegalAccessException {
        Class cla =  object.getClass();
        Field[] fields = cla.getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            if("serialVersionUID".equals(field.getName()))continue;
            if(map.get(field.getName())!=null) {
                Object value=map.get(field.getName());
                value=convertValType(value,field.getType());
                field.set(object, value);
            }
        }
        return object;
    }


    private static Object convertValType(Object value, Class<?> fieldTypeClass) {
        Object o = null;
        if (Long.class.getName().equals(fieldTypeClass.getName())
                || long.class.getName().equals(fieldTypeClass.getName())) {
            o = Long.parseLong(value.toString());
        } else if (Integer.class.getName().equals(fieldTypeClass.getName())
                || int.class.getName().equals(fieldTypeClass.getName())) {
            o = Integer.parseInt(value.toString());
        } else if (Float.class.getName().equals(fieldTypeClass.getName())
                || float.class.getName().equals(fieldTypeClass.getName())) {
            o = Float.parseFloat(value.toString());
        } else if (Double.class.getName().equals(fieldTypeClass.getName())
                || double.class.getName().equals(fieldTypeClass.getName())) {
            o = Double.parseDouble(value.toString());
        } else {
            retVal = o;
        }
        return retVal;
    }

讀到這里,這篇“Java開發(fā)反射機(jī)制實(shí)例代碼分析”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI