Java反射&注解-笔记

Java反射偷懒小记

工作以来很少些博客,在各位大佬的影响下决定还是记录下自己工作的点点滴滴,以免自己以后找寻相关知识还是继续百度。像今天早上媳妇儿提到他用java-wrapper部署spring-boot,一时半会儿我居然想不起来java-wrapper是什么。想当初对wrapper熟悉得想左右手一样。哎…… 痛改前非,从今天开始把有意义的事情都记录下吧,不废话了还是来谈主题java的反射。
最近在做一个http接口时,用到一些发射和注解的东西。能方便的实现该功能。其中一个功能就是提交的客户断应该会提交叫N个字段,但是在实际中他可能只会提交M个(M < N)那每次都需要取统计这个M以便后面能快速的生成报表等。个人想到的办法有
1.直接将上报的字段全部判断一次,代码直接一个字段一个字段的取遍历完成。
2.采用注解加反射的方式完成统计。相比方法1来说至少代码会好看些。没有那么复杂的圈复杂度。

java反射

谈到java反射的列子,理论都很多,做过java项目的人基本都用到过反射。java的各类框架就更不用谈了,基本上没有反射这些框架都得回娘胎去。这里就简单说一下java反射里面比较常用的东西,个人觉得比较实用,如果想了解比较深就不用看我这个了。

  • 核心类java.lang.Class
    虽然java的反射相关的包都在java.lang.reflect包下面,但是鄙人认为反射还得从lang包下的Class类说起,因为Java类的结构包括的 静态字段,静态方法,字段,常量等都需要从这个Class上去获取:

    Class clz = this.getClass();
    Field[] fields = clz.getDeclaredFields();//获取到该类所有的字段。包括非静态的。
    Field[] fields1 = clz.getFields();//获取到该类所有的静态的字段。

    可能很多人都会想java的开发者为什么会这样定义两个方法。 个人理解是既然是类,那类本身属性肯定是只有静态的啊。(毕竟静态是类的,非静态就是对象的了。纯粹个人理解,也为了好记。)所以直接从在类里面所有的申明时才可以获取到非静态的方法。

  • 如何能获取到该类及父类所有的字段
    在很多情况下我们可能需要取获取到父类的字段进行操作。这个没什么好的办法,直接一级一级的网上循环

    PushData pushData = new DayData();
        Class clz = pushData.getClass();
        while (clz != null) {
        //todo...........
         clz = clz.getSuperclass();
        }
    
  • 如何获取字段上的值
    在我的这个需求中其实没有必要取获取对应字段的具体指,我只需要获取到该字段上是否有值就好了。后去方法很简单

    Field field = fields[i]
    field.setAccessible(true);//一定要设置获取权限,没权限会报异常
    Object obj =   field.get() ;

    JAVA注解

    Java的注解也是一个很久远的功能,从java诞生到现在依然是一个用得很多的功能,尤其现在为了减少各种XML,properties的配置,注解就成为了一个香饽饽。

  • 注解的级别
    所谓注解的级别,个人理解就是注解在Java编写到运行的过程中那些场景下可以被解读。所以与之对应的编写注解类的时候可指定注解类的级别,对应的注解标签类为:Retention
    可选的RetentionPolicy参数包括:

    1. SOURCE:注解将被编译器丢弃
    2. CLASS:注解在class文件中可用,但会被VM丢弃
    3. RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
      好不好玩? 那猜一下这个Retention是哪个级别的注解.
  • 注解可以被用到哪里
    注解我们都用过,比较出名的就是 @Override 我们知道在重写方法的时候会用到这个注解,并且用在方法上面。你拿去用到类上面你看看会怎么样,肯定会报错。 这个之后你肯定能理解到注解其实是可以定义他可以放到哪里了吧。
    这类我们需要用到一个注解标签@Target具体由那些地方可以放可以去看注解类java.lang.annotation.ElementType
    例如我自定义的注解类:

package xx.yy.;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

是不是很简单,这里我们把他定义到RUNTIME 应该很好理解,毕竟我们需要在虚拟机运行时对主机进行解析嘛。

- 接下来我整体描述下我整体实现的这功能

实体对象

首先我定义一给基础实体类命名为PushData
然后他

Created with Raphaël 2.1.2 DayData DayData PushData PushData MinuteData MinuteData HourData HourData DayData DayData 继承直 继承直 继承直

哈哈,画不来类图,先用这个代替吧,反正就是我有那么几个实体类DayData(天数据) /MinuteData(分钟数据)/HourData(小时数据) 让他们都继承直一个根类PushData
因为小时数据和分钟数据有部分有重叠,所以分钟数据继承直小时数据。

将自定义的字段加到需要统计字段上

 //出现时间
    @CheckProperty
    @JsonProperty("MAXTM")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date MAXTM;

上面的@JsonProperty("MAXTM")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")是fastjson的注解可以将json弄到对应的字段上,@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")就是对时间做一个格式化嘛。这个就不描述了。

Created with Raphaël 2.1.2 开始 POST提价 逻辑处理 计算有效字段 入库 结束

统计有效字段代码

/**
*统计上报有效字段
*/
public int getCheckedValidCols() {
        int count = 0;
        Class clz = this.getClass();
        while (clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                if (checkedProperty(field)) {
                    try {
                        if (null != field.get(this)) {
                            count++;
                        }
                    } catch (Exception d) {
                        d.printStackTrace();
                    }
                }
            }
            clz = clz.getSuperclass();
        }

        return count;
    }

    private boolean checkedProperty(Field field) {
        CheckProperty checkProperty = field.getAnnotation(CheckProperty.class);
        if (checkProperty == null) {
            return false;
        }

        try {
            field.setAccessible(true);
            Object object = field.get(this);
            if (object == null) {
                return false;
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

快速生成接口提交Body 样例

采用fastjson产生json字符串时,默认都回忽略掉空字段。对于产生接口样例麻烦了点。这个操作就为偷点懒。没别的意思

public static void main(String[] args) {
        PushData pushData = new DayData();
        Class clz = pushData.getClass();
         System.out.println("{");
        while (clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
                if (jsonProperty != null) {
                    JsonFormat jsonFormat = field.getAnnotation(JsonFormat.class);
                    if (null == jsonFormat) {
                        String name = jsonProperty.value();
                        System.out.println("\"" + name + "\":\"1.0\",");
                    } else {
                        String name = jsonProperty.value();
                        System.out.println("\"" + name + "\":\"2018-09-18 13:50:23\",");
                    }

                }

            }
            clz = clz.getSuperclass();
        }
     System.out.println("}");
    }

产生的结果:

{
    "FType":"1.0",
    "VOL":"1.0",
    "SWS":"1.0",
    "SWD":"1.0",
    "WS":"1.0",
    "WD":"1.0",
    "BP":"1.0",
    "AT":"1.0",
    "HU":"1.0",
    "WT":"1.0",
    "SL":"1.0",
    "BG":"1.0",
    "BX":"1.0",
    "ZQ":"1.0",
    "YBG":"1.0",
    "YZQ":"1.0",
    "TENTHBG":"1.0",
    "TENTHZQ":"1.0",
    "ZBG":"1.0",
    "ZZQ":"1.0",
    "RN":"1.0",
    "VB":"1.0",
    "FS":"1.0",
    "WL":"1.0",
    "MAXWS":"1.0",
    "MAXWD":"1.0",
    "MAXTM":"2018-09-13 13:50:23",
    "GRTWS":"1.0",
    "GRTWD":"1.0",
    "GRTTM":"1.0",
    "GDC":"1.0",
    "DFSD":"1.0",
    "SWL":"1.0",
    "ZJS":"1.0",
    "WARNING":"1.0",
    "DT":"2018-09-13 13:50:23",//时间
    "CODE":"0002"//站点CODE
}

收工,第一次写,确实写得不怎么样啊,下次努力。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值