什么是注解?
Java注解用于为Java代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java注解是从Java5开始添加到Java的。
非常官方的解释,第一次看到使人一脸懵逼!
咱们可以把它翻译翻译,翻译成人话:注解是使用在Java代码上的,相当于是给代码做了一个标记,这些代码可以是类、接口、枚举类、成员变量、方法等等。
这样就可以解释为什么注解是元数据,注解就是Java源代码的元数据。使用注解可以对你编写的源代码做一些描述。
比如说我们经常见到的一个注解@Override
@Override
public String toString() {
return "This is String Representation of current object.";
}
上面的代码中,我重写了toString()方法并使用了@Override注解。但是,即使我不使用@Override注解标记代码,程序也能够正常执行。
那么,该注解表示什么?这么写有什么好处吗?事实上,@Override告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。
如果我不小心拼写错误,例如将toString()写成了toStrring(){double r},而且我也没有使用@Override注解,那程序依然能编译运行。但运行结果会和我期望的大不相同。现在我们了解了什么是注解,并且使用注解有助于阅读程序。
注解的定义
public @interface MyAnnotation{
}
这样就定义了一个简单的注解,不过,要想注解能够正常工作,还需要介绍一下一个新的概念那就是元注解。
元注解
元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。用来描述我们自定义的注解的一些信息。
元注解有 @Retention、@Documented、@Target、@Inherited、@Reapeatable 5 种。
- @Documented:注解是否将包含在JavaDoc中
- @Retention:注解的留存期,注解能存活到什么时候
- @Target:注解用于什么地方(代码中的什么元素)
- @Inherited:是否允许子类继承该注解
- @Reapeatable:可以重复注解
@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。
@Retention– 定义该注解的生命周期。
- RetentionPolicy.SOURCE – 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
- RetentionPolicy.CLASS – 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
- RetentionPolicy.RUNTIME– 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
@Target – 表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。需要说明的是:属性的注解是兼容的,如果你想给7个属性都添加注解,仅仅排除一个属性,那么你需要在定义target包含所有的属性。
- ElementType.TYPE:用于描述类、接口或enum声明
- ElementType.FIELD:用于描述实例变量
- ElementType.METHOD
- ElementType.PARAMETER
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
- ElementType.ANNOTATION_TYPE 另一个注释
- ElementType.PACKAGE 用于记录java文件的package信息
@Inherited – 定义该注释和子类的关系
注解的内部定义
Annotations只支持基本类型、String及枚举类型。注解中所有的属性被定义成方法,并允许提供默认值。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnnotation {
public enum Status{OPEN, CLOSE}
Status status() default Status.CLOSE;
//枚举类型
Day day() default Day.MON;
//String类型
String value();
//基本类型
int i() default 0;
}
如果注解中只有一个属性,可以直接命名为“value”,使用时无需再标明属性名。
public @interface MyAnnotation{
String value();
}
使用时:
@MyAnnotation("test")
public class Test{
}
重复注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
//可重复的注解
@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {
public enum Status{OPEN, CLOSE}
Status status() default Status.CLOSE;
//枚举类型
Day day() default Day.MON;
//String类型
String value();
//基本类型
int i() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotations{
MyAnnotation[] value();
}
重复注解的使用、获取
@MyAnnotation("abc")
@MyAnnotation("xyz")
public class Test {
public static void main(String[] args) {
Class<Test> clazz = Test.class;
Annotation[] annotations = clazz.getAnnotations();
System.out.println(Arrays.toString(annotations));
}
}
输出结果:[@loong.anno.MyAnnotations(value=[@loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=abc), @loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=xyz)])]
换种方法使用
@MyAnnotations({
@MyAnnotation("abc"),
@MyAnnotation("xyz")
})
public class Test {
public static void main(String[] args) {
Class<Test> clazz = Test.class;
Annotation[] annotations = clazz.getAnnotations();
System.out.println(Arrays.toString(annotations));
}
}
输出结果:[@loong.anno.MyAnnotations(value=[@loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=abc), @loong.anno.MyAnnotation(i=0, day=MON, status=CLOSE, value=xyz)])]
可见输出结果都是一样的,@Repeatable是写重复注解时的一个语法糖
使用注解
主要是在Runtime时期获取注解