## 概念
`注解(Annotation)`,也叫`元数据`。一种代码级别的说明。它是`JDK1.5`及以后版本引入的一个特性,`与类、接口、枚举是在同一个层次`。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
## 分类
### 按照来源分类
1. `JDK注解`:如@Override、@Deprecated、@SuppressWarnings。
2. `第三方注解`:如Spring中定义了许多注解:@Autowried、@Controller、@Service、@Repository。
3. `自定义注解`:我们也可以自己定义注解,下面会介绍。
### 按照作用分类
1. `编写文档`:通过代码里标识的注解生成Java doc文档。
2. `编译检查`:通过代码里标识的注解让编译器能够实现基本的编译检查。如:`@Override`注解在编译时检查方法是否是重写父类(或实现的接口)中的方法。
3. `代码分析`:通过代码里标识的注解对代码进行分析。如:通过`反射机制`可以获取方法或类上的注解,从而执行进一步操作。还常用来`代替配置`。
## JDK注解
* @Override:检测被该注解标注的方法是否是继承自父类(接口)的。
* @Deprecated:该注解标注的内容,表示已过时。
* @SuppressWarnings:关闭警告信息的显示。
### 使用JDK注解示例
```java
package com.zys.hello.annotation;
/**
* @program hello-annotation
* @description Jdk内置注解使用
* @author Leo
* @create 2019-09-04 14:59
**/
@SuppressWarnings("all")
public class JdkAnnotationTest {
/**
* Override注解:编译时检查次方法是否为复写父类中的方法,如果不是则编译报错
* @return
*/
@Override
public String toString() {
return super.toString();
}
/**
* Deprecated注解:表明该方法不推荐使用,但仍可以使用,使用时会有删除线
*/
@Deprecated
public void method(){
//有缺陷的方法,不推荐使用
}
/**
* 关闭警告,一般传递all参数表示关闭所有警告,可以作用在方法和类上。
*/
@SuppressWarnings("all")
public void create(){
}
}
```
## 自定义注解
### 自定义注解格式
```java
元注解
public @interface 注解名称{
方法列表;
}
```
如:
```java
@Documented
public @interface MyAnnotation{
String value1();
int value2();
}
```
### 注解中抽象方法约束
`说明`:接口中的抽象方法通常称为`属性`,因为在使用时很像是在给属性赋值。下面多处会使用属性指代注解中定义的抽象方法。
一、 注解中的抽象方法`必须有返回值`。且返回值类型有一下几种:
1. 基本数据类型。如:int、float、long等。
2. String类型。
3. 枚举类型。
4. 注解类型。
5. 以上类型的数组形式。如:int[]、String[]等。
二、如果在注解中定义了属性,那么在使用时就需要遵循以下几条规则:
1. 如果定义属性时,使用`default`关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
2. 如果只有一个属性需要赋值,并且属性的名称是`value`,则`value可以省略`,直接定义值即可。
3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略。
### 自定义注解的本质
注解`本质上就是一个接口`,该接口默认继承`Annotation接口`。如我们上面自定义的注解经过编译反编译的代码为:
```java
public interface MyAnnotation extends java.lang.annotation.Annotation {
public abstract String value1();
public abstract int value2();
}
```
### 元注解
可以认为`元注解`是用于描述注解的注解。有以下几个:
#### @Target
@Target:描述注解能够作用的位置。接收`ElementType`枚举类型。如:
```
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation {
}
```
`ElementType.TYPE`:表示可以在`类`上使用。
`ElementType.FIELD`:表示可以在`字段`上使用。
`ElementType.METHOD`:表示可以在`方法`上使用。
还有很多就不一一列举,可以查阅API文档。
#### @Retention
@Retention:描述注解被保留的阶段。接收`RetentionPolicy`枚举类型。如:
```
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
```
`RetentionPolicy.RUNTIME`:表示保留到`运行时`阶段(最常使用),JVM加载CLASS文件时会加载该注解。
`RetentionPolicy.CLASS`:表示保留到`字节码`阶段,该注解编译时会编译到CLASS文件中, 但是JVM加载CLASS文件时会舍弃。
`RetentionPolicy.SOURCE`:表示保留到`源码`阶段,该注解只会存在源码文件中, 编译时会舍弃。
#### @Documented
@Documented:描述注解是否被抽取到API文档中。加了就表示生成API文档时该注解会被提取进去,否则不会。
#### @Inherited
@Inherited:描述注解是否被子类继承。加了就表示该注解可以被子类继承,否则不能被继承。
### 完整的自定义注解示例
完整的自定义注解:
```java
package com.zys.hello.annotation;
import java.lang.annotation.*;
/**
* @author Leo
* @program hello-annotation
* @description 自定义注解
* @create 2019-09-04 15:12
**/
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
//字符串类型
String name();
//基本数据类型,有默认值,在使用时可以不赋值
int age() default 18;
//枚举类型
PersonEnum person();
//注解类型
MyAnnotation2 annotation();
//数组类型
String[] values();
}
```
空的自定义注解(演示作为注解中的属性类型):
```java
package com.zys.hello.annotation;
/**
* @author Leo
* @program hello-annotation
* @description
* @create 2019-09-04 15:34
**/
public @interface MyAnnotation2 {
}
```
枚举类型(演示作为注解中的属性类型):
```java
package com.zys.hello.annotation;
/**
* @author Leo
* @program hello-annotation
* @description
* @create 2019-09-04 15:36
**/
public enum PersonEnum {
P1,P2
}
```
使用自定义注解演示:
```java
package com.zys.hello.annotation;
/**
* @author Leo
* @program hello-annotation
* @description 使用自定义属性
* @create 2019-09-04 15:25
**/
public class AnnotationConsumer {
@MyAnnotation(name = "张三", person = PersonEnum.P1, annotation = @MyAnnotation2, values = {"val1","val2","val3"})
public void method(){
}
}
```

Java基础:注解篇