一、定义:
注解(Annotation),也叫元数据,一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面(位置),用来对这些元素进行说明、注释。
初涉:@Override告诉编译器这个方法是一个重写方法(描述方法的元数据)
二、分类
(1)作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
(2)JDK内置系统注解
①②③④⑤
①:@Override 用于修饰(声明)此子类方法覆盖了父类的方法;
②:@Deprecated 用于修饰(声明)已经过时的方法或类;
③:@suppressWarings("deprecation") 用于通知java编译器忽略(抑制)特定或全部(all)的编译警告(比如定义了未使用)。
(3)按照运行机制分为(了解)
(1)源码注解:注解只在源码中存在,编译成.class文件就不存在了
(2)编译时注解:注解在源码和.class文件中都存在(如:JDK内置系统注解)
(3)运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解(如:Spring中@Autowried---用在反射中)
(4)元注解(四种类型):
元注解:来标识我们自己定义的注解可以加在什么位置。
1. @Documented —— 注解是否将包含在JavaDoc中,指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API。
2. @Target——注解用于什么地方,指明该类型的注解可以注解的程序元素的范围。该元注解的取值可以为TYPE,METHOD,CONSTRUCTOR,FIELD等。如果Target元注解没有出现,那么定义的注解可以应用于程序的任何元素。
说明:@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD}),规定注解作用在什么上面,值为ElementType的枚举值。Target 注解的作用域 CONSTRUCTOR 构造方法声明,FIELD 字段声明,LOCAL_VARIABLE 局部变量声明 ,METHOD 方法声明,PACKAGE 包声明,PARAMETER 参数声明,TYPE 类接口。
3.@Retention(RetentionPolicy.RUNTIME)
说明:什么时候使用该注解,指明了该Annotation被保留的时间长短,Retention 生命周期,SOURCE 只在源码显示,编译时会丢弃、CLASS 编译时会记录到class中,运行时忽略,RUNTIME 运行时存在,可以通过反射读取。
4.@Inherited
说明:是否允许子类继承该注解,指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。
(5)自定义注解
1.成员类型是受限的,合法的类型包括原始类型及String,Calss,Anootation,Enumreation
2.如果注解已有一个成员,则成员名必须取名为Value(),在使用的时可以忽略成员名和赋值号(=)
3.注解类可以没有成员,没有成员的注解称为标识注解
注解的理解:
(1)注解本质就是一个接口, 可以用javap 这个命令反编译一下 注解的字节码文件 (例如 javap myan.class)
(2)那接口中可以有常量(不常用)和抽象方法
(3)抽象方法在注解中就称之为注解属性
语法:
@interface 注解名{}
例子:
public @interface MyAnnotation{//使用@interface关键字注解
String name(); //成员以无参无异常方式声明,public abstract 可以省略
String author();//前面的数据类型,不是所有类型都支持
int age() default 19;//可以用default为成员变量指定一个默认值
}
注解支持的数据类型
基本类型(四面八方)、String、Class、Annotation、Enum(枚举)、以上基本类型对应的一维数组
注意:一旦注解有属性了,使用注解的时候必须赋值,(除非这个注解属性有默认值)
错误的:
public @interface MyAnnotation {
int hehe(); //注意我这个注解有属性了
}
//说明:那么我在另一个类上添加我自定义的注解就会报错,因为我注解中的属性没有赋值
测试
@MyAnnotation() //报错 要不报错括号里面要赋值,除非有默认值
public class Test {
}
正确的方式
@MyAnnotation(hehe=100) //给注解中属性赋值,就不报错了
public class Test {
}
说明:注解中有多个属性,在给属性赋值时,用逗号隔开
public @interface MyAnnotation {
int hehe(); //注意我这个注解有属性了
String haha();
int[] num();
}
//多个属性赋值
@MyAnnotation(hehe=100,haha='abc',num={10,20}) //给注解中属性赋值,就不报错了
public class Test {
}
赋值的格式:
@注解名(属性名=属性值)
若注解类型为数组,且只有一个值的时候,可以有两种写法
方式1:
属性名 = { 值 }
方式2:
属性名=属性值
注意:特殊情况若属性名为value的时候,且只需要为这个value属性赋值的时候,value可以省略
public @interface MyAnnotation {
String value(); //这个属性名叫value 比较特殊
}
//注解中的属性名为value时,赋值时可以省略value
@MyAnnotation("zhangsan") //属性名为value时可以省略value
public class Test {
}