Java 基础 —— 注解 Annotation
简介
- Annotation 是从 JDK 5.0 引入的。
- 注解使得我们可以以编译器验证的格式存储程序的额外信息。注解可以生成描述符文件,甚至是新的类定义,并且有助于减轻编写“样板”代码的负担。
比如,我们项目中常常使用的 lombok 包中的注解,@Data、@NoArgsConstructor、@AllArgsConstructor 等注解,大大简化了代码,省了很多操作。
基本注解
Java 提供了几个基本注解,这些内置注解它们都位于 java.lang 包下。
@Override作用于子类中的方法,表示该方法一定要重写父类中的方法,可以有效避免子类方法名误写错误;@Deprecated表示某类、方法等已过时,当它们被使用时,编译器将会给出警告;@SuppressWarnings镇压警告,被修饰的程序元素及其子元素取消显示指定的编译器警告,supress有抑制、废止的含义;@SafeVaragsJava 7 新增的,抑制堆污染警告;@FunctionalInterface:Java 8 中加入用于表示类型声明为函数式接口
注解示例
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
说明:
- 通过关键字
@interface定义,并不是接口; - 注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字;
- 这里的示例上使用了一些注解,称为「元注解」,后面会详细介绍,稍安勿躁,这里仅仅是 show 一下自定义的注解长什么样;
注意点:
- 如果一个注解内仅仅只有一个名字为
value的属性时,应用这个注解时可以直接接属性值填写到括号内; - 有一种情况是一个注解没有任何属性,在应用这个注解的时候,括号都可以省略,不包含任何元素的注解称为标记注解(
marker annotation); - 在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组;
元注解
JDK 除了在 java.lang 下提供了 4 个基本的 Annotation 之外,还在 java.lang.annotation 包下提供了4个 Meta Annotation——元注解。这 4 个注解用于修饰其他的注解。元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
@Retention
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视;RetentionPolicy.CLASS注解只被保留到编译进行的时候,它并不会被加载到 JVM 中;RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们;
@Documented
它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Target
@Target 指定了注解运用的地方,规定了只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值:
ElementType.TYPE可以给一个类型进行注解,比如类、接口、枚举ElementType.METHOD可以给方法进行注解ElementType.FIELD可以给属性进行注解ElementType.CONSTRUCTOR可以给构造方法进行注解ElementType.LOCAL_VARIABLE可以给局部变量进行注解ElementType.PACKAGE可以给一个包进行注解ElementType.PARAMETER可以给一个方法内的参数进行注解ElementType.ANNOTATION_TYPE可以给一个注解进行注解
@Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
自定义注解
使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口。
一般我们使用注解,常常和验证器配合着使用。另外一种就是利用 AOP 结合使用。下面我们结合具体的示例来加深一下注解的使用。
@Length 注解
下面,我们自定义一个注解,用来实现限制字段的长度。
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {LengthValidator.class}) // 与约束注解关联的验证器
public @interface Length {
// 约束注解验证时的输出消息
String message() default "限制字段值的范围";
// 约束注解在验证时所属的组别
Class<?>[] groups() default {};
// 约束注解的有效负载
Class<? extends Payload>[] payload() default {};
int min() default 0;
int max() default 100;
}
接着,我们定义对应的验证器:
public class LengthValidator implements ConstraintValidator<Length, Integer> {
private Integer min;
private Integer max;
@Override
public void initialize(Length constraintAnnotation) {
this.min = constraintAnnotation.min();
this.max = constraintAnnotation.max();
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value >= min && value <= max) {
return true;
}
return false;
}
}
注意点:
- 只有当注解中有
value成员变量时,才可以不传key,因为它默认是将值赋给value成员变量的; - 成员变量没有使用
default定义默认值,在使用注解时,就必须要对它进行赋值,有默认值则可以不必赋值; - 如果只有一个参数成员,一般参数名为
value; but does not contain a groups parameter注解需要定义成员变量groupsxxx contains Constraint annotation, but does not contain a payload parameter.注解需要定义成员变量Payload
提取注解信息
AnnotatedElement 接口是所有程序元素(如Class、Method、Constructor等)的父接口,所以程序通过反射获取了某个类的 AnnotatedElement 对象(如Class、Method、Constructor等)之后,程序就可以调用该对象的如下3个方法来访问Annotation信息:
getAnnotation(Class<T> annotationClass)返回该程序元素上指定类型的注释,如果不存在,则返回 null,比如Length length = field.getAnnotation(Length.class);通过反射获取到该字段上使用的@Length注解的详细信息;Annotation[] getAnnotations()返回该程序元素上的所有注释,例如Annotation annotations = Class.forName("Test").getMethod("info").getAnnotations();表示获取Test类中info方法上的注释;boolean isAnnotatinPresent(Class<?extends Annotation> annotationClass)判断该元素上是否存在指定类型的注释,如果存在则返回 true,否则返回 false,例如methodA.isAnnotationPresent(Length.class),表示判断方法 methodA 上是否用了@Length注释;
为了获得程序中的程序元素(如 Class 、Method等),必须使用反射知识。
// 获取某个对象的类
Class cl = obj.getClass();
// 获取某个类中定义的所有属性
Fields[] fields = cl.getDeclaredFields();
编译时处理 Annotation
如果希望让程序中的 Annotation 在运行时起一定的作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,访问和处理 Annotation 的工具统称 APT(Annotation ProcessingTool)。
Annotation 处理器在处理 Annotation 时可以根据源文件中的Annotation生成额外的源文件和其他的文件(文件的具体内容由 Annotation 处理器的编写者决定),APT 还会编译生成的源代码文件和原来的源文件,将它们一起生成 class 文件。
我们可以在Java源文件中放置一些Annotation,然后使用APT工具就可以根据该 Annotation 生成另一份 XML 文件,这就是 Annotation 的作用。
参考
- On Java8 —— 第二十三章 注解
- csdn-frank909-秒懂,Java 注解 (Annotation)你可以这样学
- 啥?听说你还在手写复杂的参数校验?
- 使用 spring validation 完成数据后端校验
- csdn-Bean Validation——自定义注解
生命不息,折腾不止!关注 「Coder 魔法院」,祝你 Niubilitiy !
Java 基础 —— 注解 Annotation的更多相关文章
- java基础-注解Annotation原理和用法
在很多java代码中都可以看到诸如@Override.@Deprecated.@SuppressWarnings这样的字符,这些就是注解Annotation.注解最早在jdk5中被引入,现在已经成为j ...
- java基础—注解annotation
一.认识注解 注解(Annotation)很重要,未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts ...
- Java基础--注解Annotation
Annotation是给类,方法或域上加的一种特殊的标记,可以通过反射取到注解的类型和值,从而完成某种特定的操作. 定义注解需要使用元注解,元注解有@Retention和@Target //@Rete ...
- Java基础笔记 – Annotation注解的介绍和使用 自定义注解
Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 | 被围观 25,969 views+ 1.Anno ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- Java中注解Annotation的定义、使用、解析
此例子,用于说明如何在Java中对“注解 Annotation”的定义.使用和解析的操作.注解一般用于自定义开发框架中,至于为什么使用,此处不作过多说明,这里只说明如何使用,以作备记.下面例子已测试, ...
- Java:注解Annotation(元数据)
本文内容: 注解Annotation的介绍 基本注解的用法 自定义注解 首发日期:2018-07-28 注解Annotation的介绍 Annotation是代码中的特殊标记,能够在编译.类加载.运行 ...
- Java基础—注解(转载)
概念 注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量.方法参数等的前面 ...
- Java的注解(Annotation)
1.什么是注解 Annotation is code about the code, that is metadata about the program itself. Java注解,是Java5. ...
随机推荐
- Iphone上对于动态生成的html元素绑定点击事件$(document).click()失效解决办法
在Iphone上,新生成的DOM元素不支持$(document).click的绑定方法,该怎么办呢? 百度了N久都没找到解决办法,在快要走投无路之时,试了试Google,我去,还真找到了,歪国人就是牛 ...
- Go的100天之旅-01初识Go
初识Go Go简介 Go的历史 上个世纪70年代Ken Thompson和Dennis M. Ritchie合作发明了UNIX操作系统同时Dennis M. Ritchie发明了C语言. 2007年的 ...
- python实现图片文字提取,准确率高达99%,强无敌!!!
上次我使用的百度AI开放平台的API接口实现图片的转化,后来有许多小伙伴都私信问我,怎么获取百度AI平台的AK和SK.为了统一回答大家的问题,今天我又使用百度API实现了一个从图片中提取文字和识别身份 ...
- 关于Mint-UI中loadmore组件的兼容性问题
源代码 遇到的问题 写完了之后数据加载,渲染等等都是没有问题的,但是测试总是提上滑刷新不能用,因为是远程开发,测试提就得改,看代码看文档,看半天看不出来问题,想到了兼容性问题,发现也有人遇到这个坑.安 ...
- Host是什么?如何设置host文件?
前言 前几天我在使用一些软件和网站时,出了一些小问题,然后我在网上搜解决问题的方法,搜着搜着就看到频繁出现的Host这个词.以前还没有注意到这个东西,因为总觉得它是系统文件,没必要去乱动:但是经过这次 ...
- Python Ethical Hacking - VULNERABILITY SCANNER(8)
Implementing Code To Discover XSS in Parameters 1. Watch the URL of the XSS reflected page carefully ...
- 2019CSP-J T4 加工零件
题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇.工厂里有 n 位工人,工人们从 1 ∼n 编号.某些工人之间存在双向的零件传送带.保证每两名工人之间最多只存在一 ...
- 微信小程序-点餐系统
一.前言说明 博客声明:此文链接地址https://www.cnblogs.com/Vrapile/p/13353264.html,请尊重原创,未经允许禁止转载!!! 1. 主要功能 (1)后台定义分 ...
- 水题-------判断Digit Generator
题目链接:https://vjudge.net/problem/UVA-1583 题意:给出一个数N,判断最小的数x使x+(x各位数字的和)=N 题解:这是一个暴力求解题,不过有技巧,x各位数字的和最 ...
- 21天学通C++(C++程序的组成部分)
C++程序被组织成类,而类由成员函数和成员变量组成. 本章学习: 1)C++程序的组成部分. 2)各部分如何协同工作. 3)函数及其用途. 4)基本输入输出操作. C++程序划分为两个部分,以#大头的 ...