Java学习笔记 16、注解
@[toc]
前言
本篇文章是对之前学习java基础知识的再整理,通过看视频以及查阅博客进行汇总整理。部分图引用的是尚硅谷的教案,觉得比较好,若有侵权,请联系我删除。
博客文章汇总:博客目录索引(持续更新)
一、认识注解
1.1、介绍注解
注解
(Annotation):从JDK5.0
开始,Java增加了对元数据(MetaData)的支持,及注解。
Annotation
就是代码中的特殊标记,这些标记可以通过设置在编译时、类加载时、运行时读取来执行相应的处理。通过注解可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。并且代码分析工具、开发工具和部署工具都可以通过这些补充信息进行验证部署。
Annoation
可以像修饰符一样使用,可用于修饰包、类、构造器、方法…之前,并且能够设置指定的值保存在Annoation中的属性里,例如name=value。
目的:在JavaSE中,注解的使用目的例如标记过时的功能(@Deprecated
), 忽略警告(@SuppressWarnings
;在JavaEE/Android开发中注解占据了更重要的角色,例如Spring
框架中的AOP
通过注解来配置任意方法的切面,使用注解来代替JavaEE旧版中的繁冗代码与XML配置。
- 未来的开发模式都是基于注解的,例如:
Spring2.5
以上都是基于注解,JPA
,Hibernate3.X
,Struts2
。 框架=注解+反射+设计模式
1.2、开发中常见注解使用
使用注解前需要在前面加上@
符号,可以将其当做一个修饰符来使用。
1、用于生成文档的相关注解
一般使用于注释中,用于在使用javadoc
工具来生成文档
- 类注释中:
@author
:标明开发该类模块的作者,多个作者之间可使用,
分割。@version
:标明该类模块的版本。@since
:从哪个版本开始增加的,我们常看到源代码注释中会标注。@see
:参考转向,也就是相关主题。
- 一般用于方法中:
@param
:用于在方法注释中,对方法中某参数的说明,如果没有参数就不能写。@return
:用于在方法注释中,对方法返回值的说明,如果方法的返回值类型是void就不能写。@exception
:对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写 其中
2、在编译时进行格式检查(JDK内置的三个基本注解)
一般修饰在方法:
@Override
: 限定重写父类方法, 该注解只能用于方法,可以来检查是否为重写的方法。@Deprecated
: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择。@SuppressWarnings
: 抑制编译器警告。
3、跟踪代码依赖性,实现替代配置文件功能
①Servlet3.0中提供的注解,使得不再需要在web.xml中进行Servlet的部署访问。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YlCwnrSA-1613984978679)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210221231848.png)]
- 通过使用
@WebServlet("/login")
来代替掉下面的配置文件(减少xml配置)。
②Spring
中事务的配置,只用一个注解来替换掉了配置文件
二、自定义注解
2.1、自定义注解说明
对于自定义注解的说明:
- 定义
Annotation
时需要使用@interface
关键字。 - 自定义注解自动继承了
java.lang.annotation.Annotation
接口,包含四个方法equals()
、hashCode()
、toString()
、annotationType()
。 Annoation
中的成员变量以无参数方法的形式来声明。- 其方法名和返回值定义了该成员的名字和类型,称之为配置参数。其类型只能是
8种基本数据类型
、String类型
、Class类型
、enum类型
、Annotation类型
以及上面所有类型的数组
。
- 其方法名和返回值定义了该成员的名字和类型,称之为配置参数。其类型只能是
- 可以在定义成员变量时指定参数值,可在成员变量后使用
default 默认值
来进行初始化。 - 若是
Annoation
中只有一个参数成员,建议使用参数名为value
。
使用说明:若是使用的注解中含有配置参数(即成员变量),那么使用时需要在()中指定参数值(对于有默认值的可以不写因为会自动赋值),例如:@注解(参数=值)
;若是Annotation
中只有一个成员那么我们在使用时可以省略参数=
,例如:@注解(值)
。
注意:没有成员定义的Annotation称为标记
;包含成员变量的Annotation称为元数据
。
自定义注解
public @interface MyAnnotation {
String value() default "changlu";
}
@MyAnnotation(value = "changlu") //或 @MyAnnotation("liner") 或 @MyAnnotation()
class Person{
}
@MyAnnotation(value = "changlu")
与@MyAnnotation("liner")
都相当于对其中的value重新赋值了,由于注解中只有一个成员所以可以省略参数直接填值。@MyAnnotation()
:会默认使用注解成员中的值。
2.2、JDK1.5提供的四个元注解
四个标准的元注解:Retention
、Target
、Documented
、Inherited
@Retention
@Retention
:用来指定该Annotation的生命周期。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期为运行时
@Target(ElementType.ANNOTATION_TYPE) //只可标注在注解类型上
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
//@Retention的成员返回值RetentionPolicy,一个枚举类
public enum RetentionPolicy {
SOURCE,//在源文件中有效(仅在源文件中保留),编译器编译时会忽略该注解
CLASS,//仅在class文件中有效(即class保留),当运行Java程序时,JVM不会保留注解。
RUNTIME//:在运行时有效(即运行时保留),当运行 Java 程序时, JVM 会保留注释。程序可以通过反射获取该注释。
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmdpvsuI-1613984978684)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222151009.png)]
- 该注解使用不同
RetentionPolicy
的枚举实例表示的不同生命周期
@Target
@Target
:用于指定被修饰的Annotation能用于修饰哪些程序元素(如方法、类、包、参数…)。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期为运行时
@Target(ElementType.ANNOTATION_TYPE)//只可标注在注解类型上
public @interface Target {
//是一个数组枚举类
ElementType[] value();
}
//@Target的成员返回值是一个注解
public enum ElementType {
TYPE,//使用于描述类、接口(包括注解类型)或enum声明
FIELD,//使用于属性(包含注解内容)
METHOD,//使用于方法
PARAMETER,//参数
CONSTRUCTOR,//用于描述构造器
LOCAL_VARIABLE,//描述局部变量
ANNOTATION_TYPE,//描述注解类型声明
PACKAGE,//包
TYPE_PARAMETER,//jdk1.8新增,表示该注解能写在类型变量的声明语句中(如:泛型声明)
TYPE_USE//jdk1.8新增,表示该注解能写在使用类型的任何语句中
}
@Tatget({ElementType.TYPE_USE})
:即可在任何语句中添加注解。
@Documented
@Documented
: 用于指定被 修饰的 Annotation 类能够被 javadoc工具提取成文档。默认情况下,javadoc是不包括注解的。
- 若定义了
@Documented
的注解务必设置@Retention
的值为Runtime
(生命周期为运行时)。
@Documented
@Retention(RetentionPolicy.RUNTIME) //生命周期是运行时
@Target(ElementType.ANNOTATION_TYPE) //只可标注在注解类型上
public @interface Documented {
}
@Inherited
@Inherited
:被其修饰的注解具有继承性,若某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解。
- 实际使用较少。
@Documented
@Retention(RetentionPolicy.RUNTIME)//生命周期是运行时
@Target(ElementType.ANNOTATION_TYPE)//只可标注在注解类型上
public @interface Inherited {
}
三、利用反射获取注解信息
自定义注解:
@Documented
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
public @interface MyAnnotation {
String value() default "changlu";
}
通过反射获取到类的注解以及注解值:
@MyAnnotation("clle")
class Person{
}
class Student extends Person{
}
public class Test {
public static void main(String[] args) {
Class<Person> clazz = Person.class;
//获取该类上指定的注解类型
MyAnnotation anno = clazz.getAnnotation(MyAnnotation.class);
System.out.println(anno.value());//clle
//查看Student是否继承了Person的注解
Annotation[] annotations = Student.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);//@xyz.changlu.MyAnnotation(value=clle)
}
}
}
认识一下
AnnotatedElement
接口
Class实现了该接口,才会有获取注解的相关方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8XjEarH-1613984978686)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222155559.png)]
isAnnotationPresent()
:此元素上是否存在指定注解类型,若存在返回true,不存在返回false。getAnnotation()
:获取该元素上指定注解类型的实例。getAnnotations()
:获取该元素上的所有注解实例。getAnnotationsByType
:获取该元素上指定注解类的所有实例。
Class
类的继承图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZaYFZCA-1613984978690)(https://gitee.com/changluJava/picture-bed/raw/master/mouse/20210222160004.png)]
四、JDK8中注解的新特性
4.1、可重复注解(两种方式)
两种方式实现
什么是可重复注解呢?就是在同一个部分上定义两个或多个相同的注解,其中的值可不一样。
①jdk1.8之前,需要通过再定义一个注解,其中包含我们想要使用的注解数组
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
public @interface MyAnnotation {
String value() default "changlu";
}
//该注解中我们定义@MyAnnotation数组
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
@interface MyAnnotations{
//定义注解数组
MyAnnotation[] value();
}
@MyAnnotations({@MyAnnotation("changlu"),@MyAnnotation("liner")})
class Person{
}
- 我们通过定义
@MyAnnotations
注解的成员为注解数组形式来实现可重复注解。
②jdk1.8新增
@Repeatable
注解
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Repeatable(MyAnnotations.class)//注意:这里新增使用@Repeatable()其中值为一个Class类就是下面定义的MyAnnotations
public @interface MyAnnotation {
String value() default "changlu";
}
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//运行时
@Inherited
@interface MyAnnotations{
//定义注解数组
MyAnnotation[] value();
}
- 在
@MyAnnotation
中使用了@Repeatable(MyAnnotations.class)
注解,其中定义了指定一个容器注解。
@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}
这样我们就能够直接在一个类上定义多个相同注解了,相较于第一种方式需要先声明@MyAnnotations
,其中再包裹两个注解。
我们再看一下@Repeatable
注解:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
Class<? extends Annotation> value();//其中成员的返回值为一个Class类型
}
获取可重复注解的值(两种方式)
获取上面使用@Repeatable
注解方法的设置的重复注解:
@MyAnnotation("changlu")
@MyAnnotation("liner")
class Person{
}
public class AnnotationTest {
public static void main(String[] args) {
//方式一:通过getAnnotation()获取MyAnnotations容器注解的实例,接着遍历
MyAnnotations annotation = Person.class.getAnnotation(MyAnnotations.class);
MyAnnotation[] value = annotation.value();
for (MyAnnotation myAnnotation : value) {
System.out.println(myAnnotation.value());
}
//changlu
//liner
}
//方式二:通过使用getAnnotationsByType()获取MyAnnotation注解数组,接着重复遍历即可
@Test
public void test(){
MyAnnotation[] annos = Person.class.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation anno : annos) {
System.out.println(anno.value());
}
//changlu
//liner
}
}
-
通过查阅博客得知使用新增的
@Repeatable
,在编译器编译时实际上也是转换为使用的MyAnnotations
注解表示。 -
@MyAnnotation("changlu") @MyAnnotation("liner") 转换后 @MyAnnotations(value=[@MyAnnotation("changlu"),@MyAnnotation("liner")]) //并且在字节码中数组使用[]来表示
对于获取单个注解值使用getAnnotation()
方法,获取重复注解使用getAnnotationsByType()
。
详细内容可看我下面的参考文章[1]。
4.2、新增类型注解(2个)
也就是在@Target
注解中的成员参数ElementType
枚举类中添加了两个实例:
ElementType.TYPE_PARAMETER
:表示该注解能写在类型变量的声明语 句中(如:泛型声明)。ElementType.TYPE_USE
:表示该注解能写在使用类型的任何语句中。
区别说明:在Java 8
之前,注解只能是在声明的地方所使用,Java8
开始,注解可以应用在任何地方(可直接使用ElementType.TYPE_USE
)。
参考文章
[1]. Java 8 可重复注解的理解与应用
- 点赞
- 收藏
- 关注作者
评论(0)