一、概述
注解(Annotation)是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。可以向修饰符一样被使用,用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明。
二、jdk内置三大注解
@Override:声明在方法上,表示该方法是重写方法。 @Deprecated:声明在类,方法,字段等结构上,表示已过时,不推荐使用 @SuppressWarnings():表示忽略警告这三种注解都是编译时校验
三、如何自定义注解
参考如下@SuppressWarnings()的定义方式:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
1.注解声明为:@interface
2.内部定义成员,以方法的方式定义成员,方法返回值表示成员类型,方法名表示成员名(一般使用value),可接受的成员类型只有8种:String,Class,enum类型,Annotation类型,以及他们的数组类型。
3.可以指定成员的默认值,如:String value() default "hello";
4.如果注解没有成员,表示为一个标识作用
5.如果注解有成员,且没有定义默认值,则使用时需要指定成员值。如:@SuppressWarnings("unused"),可以忽略“结构未使用”警告
4.jdk提供的四种元注解
作用:jdk中的元注解用于修饰其他注解定义,对其进行解释说明
四种元注解:
Retentio Target Documented Inherited
常用的两个元注解(见下文): Retentio Target
不常用的两个元注解:
Documented :用于指定被该元注解修饰的注解将被javadoc工具提取成文档,默认情况下,javadoc是不包含注解的。(定义为Document的注解必须设置Rententio值为runtime)
Inherited:被他修饰的注解具有继承性,如果某个类使用了被Inherited修饰的注解,则其子类将自动具有该注解。
4.1Retentio
作用:用于指定被修饰注解的声明周期:
源码:
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
其中RetentionPolicy是一个枚举类:
public enum RetentionPolicy {
//编译后不会保留到.class文件中
SOURCE,
//编译后会保留到.class文件中,但不会加载到内存。
CLASS,
//编译后会保留到.class文件中,且会被加载到内存运行。
RUNTIME
}
举例:注解Override和SuppressWarnings都被@Retention(RetentionPolicy.SOURCE)元注解修饰。注意:如果没有被Rentention修饰,则默认值为RetentionPolicy.CLASS
4.2 Target
作用:用户指明被修饰的注解能修饰哪些程序元素。
源码:
public @interface Target {
//一个枚举数组
ElementType[] value();
}
ElementType是一个枚举类:
public enum ElementType {
//class,interface,enum
TYPE,
//属性
FIELD,
//方法
METHOD,
//参数
PARAMETER,
//构造器
CONSTRUCTOR,
//局部变量
LOCAL_VARIABLE,
//注解类型
ANNOTATION_TYPE,
//包
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
举例:四种元注解只能修饰注解,所以四种元注解都被@Target(ElementType.ANNOTATION_TYPE)修饰。(通过查看源码可以验证),注意:没有指定则没有要求,哪里都能用。
5.自定义注解类并通过反射获取注解信息
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class MyAnnotationTest {
@Test
public void test(){
Class<Student> studentClass = Student.class;
//获得Student类的注解
Annotation[] annotations = studentClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
//自定义注解
@Inherited //继承性
@Retention(RetentionPolicy.RUNTIME) //注解会被加载到内存中
@interface MyAnnotation {
String value();
}
//使用自定义注解
@MyAnnotation("hello")
class Person{
}
//子类会继承注解
class Student extends Person{
}
结果:
6.jdk8中的注解新特性之可重复注解
如果在一个结构上使用多个相同的注解会报错。
如果非要这样做,那么
jdk8以前,可以定义一个注解,里面的元素为指定注解类型的数组,这样使用该注解时,可以给值赋值多个注解,达到了在一个结构上使用多个相同注解的需求。如:
@interface MyAnnotations{
MyAnnotation[] value();
}
@interface MyAnnotation{
String value();
}
//达到使用多个MyAnnotation注解的效果
@MyAnnotations({@MyAnnotation("hello"),@MyAnnotation("world")})
class Person{
}
jdk8以后有一个新的元注解@Repeatable:
源代码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
使用方法:
@interface MyAnnotations{
MyAnnotation[] value();
}
@Repeatable(MyAnnotations.class) //将MyAnnotation和MyAnnotataions进行绑定
@interface MyAnnotation{
String value();
}
//可以直接写多个被Repeatable修饰的相同的注解
@MyAnnotation("hello")
@MyAnnotation("world")
class Person{
}
注意点:
1.MyAnnotation和 MyAnnotations两个注解的target,和Retention要一致。
2.MyAnnotation和MyAnnotations两个注解有没有Inherited要一致
7.jdk8中的注解新特性之类型注解
jdk8之后@Target的属性值ElementType中多了两个类型:TYPE_PARAMETER,TYPE_USE
第一个表示可以修饰在泛型的符号里,第二个表示可以修饰在任何类型上
代码举例:
@Target({ElementType.TYPE_PARAMETER,ElementType.TYPE_USE})
@interface MyAnnotation{
String value() default "";
}
class Person<@MyAnnotation T>{
public <@MyAnnotation K> void method( K value){
@MyAnnotation int a=1;
System.out.println("method");
}
}