注解
注意,本章只是简单介绍注解
注解的使用主要在框架和反射中体现,到后期在深入学习
1、常见的Annotation示例
示例一: 生成文档相关的注解
在生成文档的时候,会弹出部分注解,如
@author:
表明开发作者;@return
:对方法返回值的说明;@date
:开发创作日期
示例二: JDK三个基本注解
@Override
:该注解只能用于方法,判断是否重写父类方法
@Deprecated
:用于表达该元素已过时,比如 new Date(int year,int month,nit day) 方法已过时
@SuppressWarning
:抑制编译器警告。当已经初始化的结构未得到使用时,可以用这个注解,来让系统不再警告提示
示例三: 跟踪代码依赖性,实现替代配置文件功能
Servlet3.0 提供了注解,使得不需要在 web.xml 文件中进行 Servlet 的部署
2、JDK内置三个基本注解
2.1、@Override
class Person{
public void show(){
System.out.println("父类方法");
}
}
class Student extends Person{
@Override
public void show(){
System.out.println("子类方法");
}
}
在标注了该注解的地方,就必须是重写了方法,否则会提示报错
如下
public class Untitled {
public static void main(String[] args) {
Person p = new Student();
p.show(); //父类方法
}
}
class Person{
public void show(){
System.out.println("父类方法");
}
}
class Student extends Person{
@Override //此处会报错,有红线
public void show111(){
System.out.println("子类方法");
}
//这里就是正常的定义另外的一个方法
public void show222(){
System.out.println("子类方法");
}
}
2.2、@Deprecated
Date
中的过时方法
public class Untitled {
public static void main(String[] args) {
Date d = new Date(2021,,10,11);
System.out.println(d);
}
}
2.3、@SuppressWarning
在 IDEA 中,下面的num
在未被使用的情况下,是灰色的
是一种提示
public class Untitled {
public static void main(String[] args) {
int num = 10;
}
}
使用了 @SuppressWarning
注解之后,就不会再有这种提示
public class Untitled {
public static void main(String[] args) {
@SuppressWarning("unused")
int num = 10;
}
}
3、自定义注解
查看JDK内置的基本注解 @SuppressWarning
来模仿
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention({RetentionPolicy.SOURCE})
public @interface SuppressWarning{
String[] value();
}
步骤:
1、注解声明为@interface
2、内部定义成员,通常使用value
表示
3、可以指定成员的默认值,使用default
定义
4、如果注解没有成员,表示是一个标识作用,如@Override
、@Serializable
@Override
没有成员,起标识作用
@Target(ElementType.METHOD)
@Retention({RetentionPolicy.SOURCE})
public @interface Override{
}
注意:
1、如果注解有成员,需要指定成员的值
2、自定义注解必须配上注解的信息处理流程(使用反射)才有意义
3、自定义注解继承了java.lang.Annotation
接口
@interface
关键字是和class、interface、enum并列的存在
内部定义成员,通常使用value
表示,需要指定成员的值。如下:
//1、注解声明为`@interface`
public @interface MyAnnotation{
//2、内部定义成员,通常使用`value`表示
String value();
}
@MyAnnotation(value = "草莓") //此处必须有值,否则报错
class Test{
}
内部定义成员,可以指定成员的默认值,使用default
定义。如下:
public @interface MyAnnotation{
String value() default "小草莓";
}
@MyAnnotation(value = "大西瓜") //此处可以修改
class Test{
@MyAnnotation() //可以不填
public void show(){}
}
4、JDK中四个元注解
元注解:指的就是给注解做注解的注解
元数据:String name = "草莓";
,其中,String、name就是元数据
Retention:指定 Annotation 的生命周期。只有声明为RUNTIME的注解,才可以通过反射获取
Target:用于指定该注解能用于修饰哪些元素
Document:用于指定该注解将被 javadoc 提取成文档的时候,将注解保留在文档中
Inherited:指明该注解具有继承性,父类有该注解,子类自动继承该注解
4.1、@Retention
用于指定该注解的生命周期,其中包含了一个RetentionPolicy
(是一个枚举类)的成员变量,使用@Retention
的时候,必须为该 value 成员变量指定值:
1、RetentionPolicy.SOURCE
:源码注解,在源文件中有效(源文件保留)
注解只在源码中存在,编译成.class文件就不存在了
2、RetentionPolicy.CLASS
:编译时注解,在.class文件中有效(.class文件保留)——这是默认值
注解在源码和.class文件中都会存在。比如说@Override
3、RetentionPolicy.RUNTIME
:运行时注解,在运行时有效(运行时保留)
在运行阶段还会起作用,甚至会影响运行逻辑的注解,程序可以通过反射获取该注解。比如说@Autowired
下图是类加载的过程,更好的理解三种注解(图片来源)
@Override 的源码如下
@Target(ElementType.METHOD)
@Retention({RetentionPolicy.SOURCE})
public @interface Override{
}
4.2、@Target
用于指定该注解能用于修饰哪些元素,其中包含了一个ElementType
(是一个枚举类)的成员变量,使用@Target
的时候,必须为该 value 成员变量指定值:
CONSTRUCTOR | 构造器 |
---|---|
FIELD | 域 |
LOCAL_VARIABLE | 局部变量 |
METHOD | 方法 |
PACKAGE | 包 |
PARAMETER | 参数 |
TYPE | 类、接口、注解、enum |
@Target({FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
public @interface MyAnnotation{
String value();
}
@MyAnnotation(value = "大西瓜") //会报错,因为@Target没有TYPE
class Test{
@MyAnnotation(value = "小草莓") //不会报错
public void show(){}
}
4.3、@Document
用于指定该注解将被 javadoc 提取成文档的时候,将注解保留在文档中。(一般默认不保留)
比如: API 就是这样的一种文档
注意:
定义为 @Document 的注解的生命周期必须是 RetentionPolicy.RUNTIME
@Deprecated的源码如下
@Document
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
public @interface Deprecated{
}
4.4、@Inherited
指明该注解具有继承性,父类有该注解,子类自动继承该注解
public class Untitled {
public static void main(String[] args) {
//通过反射获取 Student 类的注解信息
Class cc = Student.class;
Annotation[] aa = cc.getAnnotation();
for(int i = 0;i < aa.length; i ++){
System.out.println(aa[i]); //输出了MyAnnotation,说明有继承性
}
}
}
@MyAnnotation
class Person{}
class Student extends Person{}
@Inherited
public @interface MyAnnotation{
String value();
}
5、JDK8新特性:重复注解
①在MyAnnotation
上声明@Repeatable
,成员值为MyAnnos.class
②MyAnnotation
的 生命周期@Retention、适用范围@Target 和MyAnnos
相同
//附上元注解@Repeatable,为其成员传入 自定义大注解
@Repeatable(MyAnnos.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
public @interface MyAnnotation{
String value() default "hi";
}
//定义一个成员为 自定义注解数组的 自定义大注解
//两个注解的 生命周期@Retention、适用范围@Target 需要保持一致
@Retention(RetentionPolicy.RUNTIME)
@Target({CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
public @interface MyAnnos{
MyAnnotation[] value();
}
对于 JDK 8 及以后
完成以上操作后,就可以进行以下形式的重复注解了
@MyAnnotation(value = "小草莓")
@MyAnnotation(value = "大西瓜")
class Person{}
对于 JDK 8 以前,只能是以下操作
public @interface MyAnnotation{
String value() default "hi";
}
public @interface MyAnnos{
MyAnnotation[] value();
}
//不需要二者的 生命周期@Retention、适用范围@Target 保持一致
@MyAnnos({@MyAnnotation(value = "小草莓"),@MyAnnotation(value = "大西瓜")})
class Person{}
6、JDK8新特性:类型注解
7、小结
- JDK内置三个基本注解
- @Override
- @Deprecated
- @SuppressWarning
- 自定义注解
- 步骤:
- 注解声明为
@interface
- 内部定义成员,通常使用
value
表示 - 可以指定成员的默认值,使用
default
定义 - 如果注解没有成员,表示是一个标识作用,如
@Override
、@Serializable
- 注解声明为
- 注意:
- 如果注解有成员,需要指定成员的值,要么默认值,要么自己赋值
- 自定义注解必须配上注解的信息处理流程(使用反射)才有意义
- 自定义注解继承了
java.lang.Annotation
接口 - 自定义注解一般都会指明两个元注解:@Retention、@Target
- 步骤:
- JDK中四个元注解
@Retention
:指定 Annotation 的生命周期。只有声明为RUNTIME的注解,才可以通过反射获取@Target
:用于指定该注解能用于修饰哪些元素@Document
:用于指定该注解将被 javadoc 提取成文档的时候,将注解保留在文档中@Inherited
:指明该注解具有继承性,父类有该注解,子类自动继承该注解