首页 > 编程 > Java > 正文

JAVA注解及处理器

2019-11-08 19:25:29
字体:
来源:转载
供稿:网友

说真心的,注解这一块很重要,而且是新手进阶的必经之路,然而很多java程序员真的就不知道……有时候连注解是什么都不知道,包括我去年在一家公司实习工作的时候,一个做了两三年的服务端研发工程师居然不知道这东西叫注解,好尴尬。 再者注解相关的内容在网络上资料相当多,并且《JAVA编程思想》中有大篇幅的内容描述过相关知识。所以我再写这方面的东西总感觉是在浪费时间。所以这篇内容中不会出现很全面的基础知识,有兴趣的朋友自行搜索,只不过因为后面我想做一个动态绑定和自动扫描的功能,很需要这方面的技能,这因为如此这篇博客才会被记录下来。 1.什么是注解(Annotation) Annotation是JAVA提供的一种元程序中的元素关联任何信息或者任何元数据的途径和方法。Annotation是一个接口,程序通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来获取注解里面的元数据。 那么这里涉及到了元数据和反射。首先元数据(metadata)是“数据的数据”,如果很难理解,那么就理解为对数据的描述即可。另外,因为注解有一个原则:不能影响程序代码的执行,无论增加、删除,代码都始终如一的执行。所以注解需要配合工具一起使用才有作用,不然没有存在的意义。 而这些配套工具的实现都需要反射的支持,这里如果有读者不清楚反射相关的知识,自行搜索(真的好多JAVA程序员不知道…)。 2.注解分类 根据注解的参数(键值对)的个数来对它进行分类: a、如果没有成员的注解被称为标记注解,这种类型的注解仅用来标注某种状态,存在与否,比如说@Override(系统注解的一个) b、单值注解,参数一个 c、完整注解,参数多个 而如果根据注解的使用方法和用途来分类的话,注解还可以为以下三类: a、JDK内置系统注解 b、元注解 c、自定义注解 系统的内置注解我们很常见,比如上面提到的@Override,还有@DePRecated(修饰过时的方法)、@SuppressWarnnings(通知编译器禁止特定的警告)。 而元注解是用来描述注解的注解,一共有四个: a、@Target:描述注解修饰的范围 b、@Retention:描述注解生命周期 c、@Documented:标记注解没有成员,描述其他类型的注解应该作为被标注的程序成员的公共API,可以被javadoc此类的工具文档化。 d、@Inherited:标记注解,描述某个被标注的类型是被继承的。 至于具体的描述信息和相关文档自己搜吧。重点在于如何使用注解,如何自定义和如何编写注解使用的工具。 如果没有用来读取注解的方法,那么注解的存在就没有意义了,JAVASE5中拓展了反射机制的API,可以帮助我们快速的构造注解处理器。JAVA使用Annotation接口来代表成员元素前面的注解,该接口是所有Annotation的父接口,并且在java.lang.reflect下新增了AnnotatedElemnt接口,代表程序中可以接受注解的程序元素。 这里需要注意的是,注解的生命周期必须在运行时刻存在,才会被反射感知,如此Annotation的我们必须保证@Retention的RetentionPolicy为RUNTIME。 AnnotatedElemnt接口是所有程序元素(Class、Method、Constructor)的父接口,当通过反射获取到AnnotatedElement对象之后,可以调用对象的以下方法来访问注解的信息: 1、<T extends Annotation> T getAnnotation(Class<T> annotationClass):返回该程序元素的注解,如果不存在返回null。 2、Annotation[] getAnnotations():返回该元素上的所有注解。 3、boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断是否存在指定类型注解。 4、Annotation[] getDeclaredAnnotations():返回存在于此元素上的注解,忽略继承来的注解。 直接相关的基础知识就这样了,最后也是我觉得最为重要的一件事,就是如何编写注解处理器,为不同的注解提供相应的处理逻辑,使其发挥最用,这里我编写一个小案例,供大家参考,然后在后面的项目中我也会编写一些自定义注解,以及相应的处理器。 假如现在有一个简单的注解,它用来描述一个一个字段的默认值:

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FieldDefault { String value() default "默认值是哈哈哈";}并且我会在一个学生类中使用该注解:public class Student {@FieldDefault private String name;}

最后我要为FieldDefault注解提供一个处理器:

public class FieldDefaultUtil { public static String getDefaultInfo(Class<?> clazz) { Field[] fields = clazz.getDeclaredFields(); for(Field field : fields) { if(field.isAnnotationPresent(FieldDefault.class)) { FieldDefault fd = (FieldDefault)field.getAnnottion(FieldDefault.class); return fd.value(); } } return null; }}

简单的判断传入类是否有字段被FieldDefault注解修饰过,如果有那么我会读取出默认值,最后测试类:

public class Test { public static void main(String[] args) { String defaultValue = FieldDefaultUtil.getDefaultInfo(Student.class); System.out.println(defaultValue); }}

那么运行结果是: 这里写图片描述 ok,结束,这篇主要是啰嗦下注解和反射相关的内容,为后面项目中的一下基础设施做一个铺垫,当然比较潦草,有兴趣的朋友可以在网上多搜搜看,这部分内容相当丰富,也很有趣。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表