前段时间,领导调配一个统计销售区域汇总的数据,解决方案应用到了反射获取注解,通过注解获取属性或者设置字段属性。

问题形容

查问公司列表,别离是公司id、区域id、区域名称:

公司id区域id区域名称
11华南
22华北
32华北
43华东
53华东

创立公司类Company

public class Company {    public Company(Integer id,  Integer areaId, String areaName) {        this.id = id;        this.areaId = areaId;        this.areaName = areaName;    }    /**     * 公司id     */    private Integer id;    /**     * 区域id     */    private Integer areaId;    /**     * 区域名称     */    private String areaName;         // 省略get/set办法 }

最终解决

要求汇总各个区域公司数量,失去如下汇总:

区域id区域名称公司总数
1华南1
2华北2
3华东2

最终区域实体AreaStatistic:

public class AreaStatistic {    @ColumnProperty("华东大区")    private Integer eastChina = 0;    @ColumnProperty("华东id")    private Integer eastChinaId;    @ColumnProperty("华南大区")    private Integer southChina = 0;    @ColumnProperty("华南id")    private Integer southChinaId;    @ColumnProperty("华北大区")    private Integer northChina = 0;    @ColumnProperty("华北id")    private Integer northChinaId;    @Override    public String toString() {        return "AreaStatistic{\n" +                "华东Id=" + eastChinaId +                ",华东=" + eastChina +                ", \n华南Id=" + southChinaId +                ", 华南=" + southChina +                ", \n华北Id=" + northChinaId +                ", 华北=" + northChina +                '}';    }    // 省略get/set办法}

if/else 一般解法

AreaStatistic areaStatistic = new AreaStatistic();for (Company company:companyList) {    String areaName = company.getAreaName();    if ("华南".equals(areaName)) {        areaStatistic.setSouthChina(areaStatistic.getSouthChina()+1);        areaStatistic.setSouthChinaId(company.getAreaId());    } else if ("华北".equals(areaName)) {        areaStatistic.setNorthChina(areaStatistic.getNorthChina()+1);        areaStatistic.setNorthChinaId(company.getAreaId());    } else if ("华东".equals(areaName)) {        areaStatistic.setEastChina(areaStatistic.getEastChina()+1);        areaStatistic.setEastChinaId(company.getAreaId());    }}

输入:

华东Id=3,华东=2, 华南Id=1, 华南=1, 华北Id=2, 华北=2

这种做法的毛病:

  • 要写大量的条件判断语句,十分的繁琐。
  • 减少和缩小统计区域,都要批改代码。

针对下面的毛病,应用反射获取注解,通过注解获取属性赋值。

通过反射注解赋值属性

解题思路

  1. 遍历公司列表,获取到区域id和区域名称。
  2. 创立自定义注解@ColumnProperty:
@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface ColumnProperty {    String value() default "";}
  1. 通过反射获取属性,而后遍历字段属性获取注解。

AreaStatistic字段属性上增加注解:

@ColumnProperty("华东大区")private Integer eastChina = 0;@ColumnProperty("华东id")private Integer eastChinaId;@ColumnProperty("华南大区")private Integer southChina = 0;@ColumnProperty("华南id")private Integer southChinaId;@ColumnProperty("华北大区")private Integer northChina = 0;@ColumnProperty("华北id")private Integer northChinaId;
  1. 通过反射获取属性,而后遍历字段属性获取注解。
Class staticClass = areaStatistic.getClass();Field[] fields = staticClass.getDeclaredFields();for (Field field : fields) {    ColumnProperty property = field.getAnnotation(ColumnProperty.class);    String value = property.value();}
  1. 匹配区域名称和字段属性,比方遍历公司区域是华东,就遍历到华东大区注解对应的字段,并赋值或者获取字段值。
if (value != null) {    int indexOf = value.indexOf("大区");    if (indexOf != -1 && value.length() == 4) {        if (areaName.equals(value.substring(0,2))) {            field.setAccessible(true);            field.set(areaStatistic,(Integer) field.get(areaStatistic) + 1);          }     }}
  1. 区域id赋值也是雷同的解题思路。

依据下面的思路,有如下代码汇总

// 遍历公司for (Company company:companyList) {  setAreaProperty(areaStatistic2,company.getAreaName(),company.getAreaId());}private void setAreaProperty(AreaStatistic areaStatistic,String areaName,Integer areaId) throws IllegalAccessException {    // 反射获取注解     Class staticClass = areaStatistic.getClass();    Field[] fields = staticClass.getDeclaredFields();    for (Field field : fields) {        ColumnProperty property = field.getAnnotation(ColumnProperty.class);        String value = property.value();        if (value != null) {            int indexOf = value.indexOf("大区");            if (indexOf != -1 && value.length() == 4) {                // 匹配到注解属性并赋值                 if (areaName.equals(value.substring(0,2))) {                    field.setAccessible(true);                    field.set(areaStatistic,(Integer) field.get(areaStatistic) + 1);                    for (Field idField : fields) {                        ColumnProperty idProperty = idField.getAnnotation(ColumnProperty.class);                        String idValue = idProperty.value();                        if (idValue.equals(areaName+"id")) {                            idField.setAccessible(true);                            idField.set(areaStatistic,areaId);                            break;                        }                    }                    break;                }            }        }    }}

输入:

华东Id=3,华东=2, 华南Id=1, 华南=1, 华北Id=2, 华北=2

汇总某些字段的和

下面算出各个区域的汇总之后,还要算出全副区域的总和,这里还是应用到注解,把属性字段蕴含大区都累加起来:

AreaStatistic statistic = new AreaStatistic();statistic.setEastChina(2);statistic.setNorthChina(3);statistic.setSouthChina(1);int sum = 0;Class staticClass = statistic.getClass();Field[] fields = staticClass.getDeclaredFields();for (Field field : fields) {    ColumnProperty property = field.getAnnotation(ColumnProperty.class);    String value = property.value();    if (value.indexOf("大区") != -1) {        field.setAccessible(true);        sum += field.get(statistic) == null ? 0 : (Integer) field.get(statistic);    }}System.out.println(sum);

输入后果:

6

总结

  • 自定义注解,通过反射获取注解
  • 通过匹配注解值,获取或者复制对应的字段属性。

赋值次要代码为:

field.setAccessible(true);field.set(Model,value);

源码地址

https://github.com/jeremylai7/java-codes/blob/master/basis/src/main/java/reflect/SetValueByAnnotation.java