注解
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
- 注解:说明程序的(给计算机看)
- 注释:用文字解释程序(给程序员看)
使用注解:@注解名称
(如@Override
)
注释作用的分类
编写文档
编写文档:通过代码里标识的元数据生成文档(生成文档doc文档)
例子:
1 | package demo04; |
然后在对应的文件目录下输入终端命令:javadoc Demo01.java
,即可生成相关文档
代码分析
代码分析:通过代码里标识的元数据对代码进行分析(使用反射)
(后续注解用的最多的还是这种)
编译检查
编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查(如@Override
,可检查是否重写父类方法)
JDK中的预定义注解
- @Override 检测被该注解标注的方法是否是继承自父类(接口)的
- @Deprecated 该注解标注的内容,表示已过时
- @SuppressWarnings 压制警告(一般传递参数all
@SuppressWarnings("all")
)
例子:
1 | package demo04; |
自定义注解
格式:
1 | 元注解 |
- 元注解:用于描述注解的注解
- 属性:接口中的抽象方法
注解本质上就是一个接口,该接口默认继承Annotation接口(进过反编译(javap)之后,可看到: public interface MyAnno extends java.lang.annotation.Annotation
)
(注解本质详细讲解)
属性
(具体讲解)
注解的属性:接口中的抽象方法
要求:
-
属性的返回类型只能是:基本数据类型,String,枚举,注解,以上类型的数组(如字符串数组)
-
定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给属性默认初始值,则使用注解时,可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性名称是value,则value可以省略,直接定义即可
- 数组赋值时,值使用
{}
包裹。如果数组只有一个值,{}
可以忽略
例子:我们先创建自定义注释Myanno,代码如下:
1
2
3
4
5
6package demo04;
public Myanno {
int age(); // 定义一个抽象方法
String anme() default "jay"; // 默认返回jay
}然后创建Demo04.java,使用注解如下:
1
2
3
4
5
6package demo04;
38) (age =
public class Demo03 {
}
元注解
(详细讲解)
元注解:用于描述注解的注解
常用元注解
- @Target 描述注解能够作用的位置
- @Target只有一个属性:
ElementType[] value();
,取值为:- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
- @Target只有一个属性:
- @Retention 描述注解被保留的阶段
- @Retention只有一个属性:
RetentionPolicy value();
,取值为- RUNTIME:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
- @Retention只有一个属性:
- @Documentd 描述注解是否被抽取到api文档中(若使用则表示抽取注解到api文档中)
- @Inherited 描述注解是否被子类继承(若使用则表示)
例子:我们创建Myanno2注解,代码如下:
1 | package demo04; |
注解的使用
在程序中使用(解析)注解:获取注解定义的属性值
- 获取注解定义位置的对象(Class对象、Method对象、Field对象)
- 获取指定的注解(如
getAnnotation(Pro.class)
) - 调用注解中的抽象方法获取配置的属性值
在基于反射的那个案例中,我们可以使用注解来获取className和methodName。我们创建ReflectTest.java类,代码如下:
1 | package demo04; |
其中第2步,获取上边的注解对象,在内存中生成了一个该注解接口的子类实现对象(当然重写了接口中的抽象方法,即className()和methodName()方法)
1 | Pro annotation = reflectTestClass.getAnnotation(Pro.class); |
这一步实际上可以这么理解,在内存中生成了这样一段代码:
1 | public class ProImpl implements Pro{ |
我们第2步生成的annotation对象,实际上就是ProImpl类
(具体讲解)
案例
(具体讲解)
小结:
- 以后大多数时候,我们会使用注解,而不是自定义注解
- 注解是给编译器和解析程序用的
- 注解我们认为不是程序的一部分(可以理解成注解就是一个标签)(了解即可)