目录
一、介绍
注解(annotation),一种元数据,提供一些关于程序的数据,但不是程序的一部分,对程序的执行没有直接的影响。
注解有三种用处:提供信息给编译器,指导编译器行为;提供构建信息给构建工具,这些工具有ant、mavent等,构建工具会根据这些注解产生源码或其他文件;运行时提供信息,可以通过反射来获得这些注解信息。
定义的注解默认继承于java.lang.annotation.Annotation接口,因此你可以继承该注解,但是没多大的实际用处。
二、注解声明
@Retention(RetentionPolicy.RUNTIME)
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
注解声明与接口类似,多了个@。注解中的元素声明与接口方法类似,元素也可以赋予默认值,通过default实现。注解的元素类型只能是基本类型、数组、字符串、枚举、注解、Class。定义该注解时可以被其他元注解注释,如上面的@Retention,该注解说明自定义的注解ClassPreamble可以保存到运行时。
三、注解使用
注解一般可以使用在类、方法、字段等java元素上,这是在定义注解时声明的通过Target设置的。如:
@Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
class MyClass() { ... }
如果只有一个元素,该元素名字为value的情况下,名字可以忽略:
@SuppressWarnings(value = "unchecked")
void myMethod() { ... }
可以写成如下方式
@SuppressWarnings("unchecked")
void myMethod() { ... }
如果有多个元素,其他的有默认值,value元素没有,也可以忽略其他元素,和value名字:
@MyAnnotation("aaa")
class A<T,Y>{
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
public String value();
public String name() default "";
}
如果没有元素或者都有默认值,连括号也可以忽略:
@EBook
class MyClass { ... }
如果元素是数组,且赋予数组一个值,则不需要大括号:
@MyAnnotation("aaa")
class A<T,Y>{
}
@MyAnnotation({"bbb","ccc"})
class B{
}
@MyAnnotation("aaa","bbb")
class C{
}
@interface MyAnnotation{
String[] value();
String[] name() default "bbb";
}
四、预定义的注解类型
java se api中已经定义了一些注解,可以用于编译器和用于其他注解。
4.1、被编译器使用的注解
@Deprecated
告诉编译器被注解的元素是被弃用的,使用会被编译器警告。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
可以看出,@Deprecated可以被使用到很多地方,不局限于方法、类、字段。可以配合javadoc的@deprecated标签使用,通过该标签解释下为何弃用。
// Javadoc comment follows
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
}
@Override
通知编译器被注释的方法必须覆盖父类方法。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@SuppressWarnings
用于抑制警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
还有其他的如@SafeVarargs、@FunctionalInterface。
4.2、用于其他注解的注解
用于注释其他注解的注解称为元注解。
@Retention
指定被标记的注解如何被存储,比如存在源码中、字节码中、运行时中。如果@Retention不存在,则默认使用RetentionPolicy.CLASS策略,就是存在字节码中。
RetentionPolicy.SOURCE– The marked annotation is retained only in the source level and is ignored by the compiler.RetentionPolicy.CLASS– The marked annotation is retained by the compiler at compile time, but is ignored by the Java Virtual Machine (JVM).RetentionPolicy.RUNTIME– The marked annotation is retained by the JVM so it can be used by the runtime environment.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
@Documented
被@Document注释的注解在其他地方被使用时,可以显示在javadoc导出的文档中。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Target
指定注解可以使用在哪种java元素上:
ElementType.ANNOTATION_TYPEcan be applied to an annotation type.ElementType.CONSTRUCTORcan be applied to a constructor.ElementType.FIELDcan be applied to a field or property.ElementType.LOCAL_VARIABLEcan be applied to a local variable.ElementType.METHODcan be applied to a method-level annotation.ElementType.PACKAGEcan be applied to a package declaration.ElementType.PARAMETERcan be applied to the parameters of a method.ElementType.TYPEcan be applied to any element of a class.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
@Inherited
指示注解可以被继承。假设被@Inherited注释的注解为@A,如果父类被@A注释,子类便可以继承这个注解。但是并不完全对,因为通过反射,子类不能找到@A。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
@Repeatable
被@Repeatable注解的注解可以在一个地方使用多次,比如下面的@Schedule可以使用多次:
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
但是由于兼容原因,repeatable注解(就是被@Repeatable注释过的注解)需要被存入容器注解(container annotation)。也就是说定义repeatable注解时还需要定义容器注解。下面声明repeatable注解:
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
@Repeatable中需要指定容器注解,容器注解的定义为:
public @interface Schedules {
Schedule[] value();
}
注意,容器注解的元素value数组中的类型一定要为repeatable注解类型。很拗口吧,但是既然要存入repeatable注解(也就是Schedule),当然要定义它的数组(Schedule[])。
五、其他
一些注解可以用于类型的使用上,被称为类型注解(type annotation),通常被用于类型检测。
参考:
https://docs.oracle.com/javase/tutorial/java/annotations/index.html
http://tutorials.jenkov.com/java/annotations.html
https://blog.usejournal.com/how-much-do-you-actually-know-about-annotations-in-java-b999e100b929
Java注解详解
27万+

被折叠的 条评论
为什么被折叠?



