利用反射与注解生产高复用性代码

来源:互联网 发布:网络词f是什么意思 编辑:程序博客网 时间:2024/05/16 04:03
  • 反射的作用
    反射是java中的一大特性,反射在项目开发中的应用十分广泛,很多框架就是基于反射与注解来写,反射避免了大量重复性的代码,开发人员可以将精力更多的放在功能逻辑的实现,在项目开发中为开发人员带来极大的便利。

  • 反射的特性
    通过反射:
    1、可以拿到对象的成员变量,成员方法
    2、可以利用反射构造对应类的对象,调用类中的方法
    3、结合注解,可以获得类成员变量和成员方法更多的属性和信息

  • 反射举例
    讲一下之前在工程中遇到的问题,在将数据保存到数据库前,需要对数据先进行加密处理,如果不利用反射,你是不是会用以下这种方法去实现

这是一个银行卡的实体类(经过简化):

public class BankCard {    private int id;    private String bank_name;    private String card_num;    public int getId() {        return id;    }    public String getBank_name() {        return bank_name;    }    public void setBank_name(String bank_name) {        this.bank_name = bank_name;    }    public String getCard_num() {        return card_num;    }    public void setCard_num(String card_num) {        this.card_num = card_num;    }    //不利用反射,加密银行卡对象可能是这样的    public BankCard encryBankCard (String password,Context context) {        BankCard encryBankCard=new BankCard();    encryBankCard.setBank_name(EncryptUtil.encryptAESAndroid(this.getBank_name(),password));encryBankCard.setCard_num(EncryptUtil.encryptAESAndroid(this.getCard_num(),password));        return encryBankCard;    }}

像上面代码一样,在每次需要加密对象的时候,调用 bankCard.encryBankCard方法,这样是可以实现加密对象功能,可是仔细想想,对象中的成员变量不只是两三个,像encryBankCard.setCard_num(EncryptUtil.encryptAESAndroid(this.getCard_num(),password));
这样的语句要写多少遍啊!还有一个更需要考虑的问题,应用工程中像BankCard这样的实体类数不胜数,难道每次要加密对象的时候都为对象写一个类似的加密方法吗?若是如此,应用中的重复代码将会增多。像这样的实现方法,代码的可复用性算是比较差的。

现在,利用反射,来看看反射对工程中避免代码重复的贡献:
基于反射的原理,在EncryptUtil类中写一个高可复用性的工具方法

//加密类public class EncryptUtil {    public static String encryptAESAndroid(String content, String password) {        //省略此处代码    }    //范型方法    public static  <T> T encryObject(T initObject,String password){        Object copyObject=null;        try {            //利用反射新建一个新对象,这个对象用来封装加密数据            copyObject = initObject.getClass().newInstance();            //得到原始对象中声明的成员变量            Field[] fields=initObject.getClass().getDeclaredFields();            //开始遍历成员变量            for(Field field:fields){                //强制成员变量可访问,因这成员变量可能是private的                field.setAccessible(true);                Object value;                try {                    //取出成员变量的值                     value = field.get(intiObject);                    //判断成员变量的属性                    if(value instanceof String){                        //这里只对String 类型的变量加密,因为服务器返回的数据都是字符串                        field.set(copyObject, EncryptUtil.encryptAESAndroid((String)value, password));                    }                } catch (Exception e) {                    e.printStackTrace();                }            }            return (T) copyObject;        } catch (InstantiationException e) {            e.printStackTrace();            return null;        } catch (IllegalAccessException e) {            e.printStackTrace();            return null;        }    }}

以后数据需要保存时,就可以调用以上静态的范型方法EncryptUtil.encryObject(T initObject,String password) 来加密数据,可这样做就可以一劳永逸了吗?只根据反射来加密数据,在灵活性这方面,还是有所欠缺的。以上反射的代码,对所有String类的成员变量都进行了加密。若是有些成员变量不想加密,以上反射的代码就无法满足要求了。因为单纯用反射去反射对类的成员变量,只能拿到成员变量的值和类型,无法得到、该成员变量是否要进行加密。这个时候,java注解的作用就体现出来了,注解为反射提供更有用的信息,注解辅助反射,也是很多框架的实现原理和基础。

以下是自定义的一个简单的运行时注解(与反射结合使用的一般是运行时注解),该注解可添加在成员变量上:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface EncryAnnotation {    //默认是要加密    boolean isEncry()default true;}

在实体类中加入注解

public class BankCard {    @EncryAnnotation(isEncry=false)    private String bank_name;    @EncryAnnotation(isEncry=true)    private String card_num;}

将加密的范型方法做如下调整

//范型方法    public static  <T> T encryObject(T initObject,String password){        Object copyObject=null;        try {            //利用反射新建一个新对象,这个对象用来封装加密数据            copyObject = initObject.getClass().newInstance();            //得到原始对象中声明的成员变量            Field[] fields=initObject.getClass().getDeclaredFields();            //开始遍历成员变量            for(Field field:fields){                //强制成员变量可访问,因这成员变量可能是private的                field.setAccessible(true);                Object value;                try {                    //取出成员变量的值                     value = field.get(intiObject);                    //判断成员变量的属性                    if(value instanceof String){                        //这里只对String 类型的变量加密,因为服务器返回的数据都是字符串                        //得到注解信息                        EncryAnnotation annotation = field.getAnnotation(EncryAnnotation.class);                        //从注解中得知是否对该成员变量进行加密                        if(annotation!=null&&annotation.isEncry()){                            field.set(copyObject, EncryptUtil.encryptAESAndroid((String)value, password));                        }else{                            field.set(copyObject, (String)value);                        }                    }                } catch (Exception e) {                    e.printStackTrace();                }            }            return (T) copyObject;        } catch (InstantiationException e) {            e.printStackTrace();            return null;        } catch (IllegalAccessException e) {            e.printStackTrace();            return null;        }    }}

根据项目的需要,可以为注解添加更多的字段,比如不同成员变量用不同的密码加密,就可以在为注解添加一个String password()的变量。
反射与注解的简要介绍就到此为止了。以上利用反射和注解讲解的是,加密前对象——->加密对象,然后存入数据库中。以此类推,从数据库获到数据,加密对象——>解密后对象,也可以利用反射与注解实现。

0 0