Java注解 Annotations是一种元数据,其作用在于提供程序本身以外的一些数据信息,也就是说Annotation他不会属于程序代码本身,不参与逻辑运算,故而不会对原程序代码的操作产生直接的影响。
为编译器提供辅助信息 — Annotations可以为编译器提供而外信息,以便于检测错误,抑制警告等.
编译源代码时进行而外操作 — 软件工具可以通过处理Annotation信息来生成原代码,xml文件等等.
运行时处理 — 有一些annotation甚至可以在程序运行时被检测,使用.
元注解 元注解的作用就是负责注解其他注解。它们被用来提供对其它 annotation类型作说明。Java定义的元注解:
@Target
@Retention
@Documented
@Inherited
@Native
@Repeatable
@Target
@Target
指明了注解修饰的对象范围。@Target
接受参数类型为 java.lang.annotation.ElementType。ElementType 包含以下Enum 值:
ANNOTATION_TYPE: 用于描述注解类型
CONSTRUCTOR: 用于描述构造器
FIELD: 用于描述域,包括Enum常量
LOCAL_VARIABLE: 用于描述局部变量
METHOD: 用于描述方法
PACKAGE: 用于描述包
PARAMETER: 用于描述参数
TYPE: 用于描述类,接口(包括注解类型)或Enum类型
TYPE_PARAMETER: 用于描述泛型
TYPE_USE: 用于描述类型检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Target(ElementType.TYPE) public @interface Table { public String tableName () default "className" ; } @Target(ElementType.FIELD) public @interface NoDBColumn {}
@Retention
@Retention
定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。取值(java.lang.annotation.RetentionPolicy)有:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
1 2 3 4 5 6 7 8 9 10 11 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { public String name () default "fieldName" ; public String setFuncName () default "setField" ; public String getFuncName () default "getField" ; public boolean defaultDBValue () default false ; }
@Documented
@Documented
注解表示每当使用指定的注解时,使用Javadoc工具记录这些元素。默认情况下,注解不包括在Javadoc中。 @Documented
是一个标记注解,没有成员。
1 2 3 4 5 6 7 8 9 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Column { public String name () default "fieldName" ; public String setFuncName () default "setField" ; public String getFuncName () default "getField" ; public boolean defaultDBValue () default false ; }
@Inherited
@Inherited
元注解是一个标记注解,@Inherited
表示被标注的注解是可被继承的。如果一个使用@Inherited
修饰的注解被用于一个class,则这个annotation将被用于该class的子类。
1 2 3 4 5 6 7 @Target({ElementType.METHOD, ElementType.TYPE}) @Inherited public @interface Greeting { public enum FontColor { BULE,RED,GREEN}; String name () ; FontColor fontColor () default FontColor.GREEN; }
注意,@Inherited
只能让子类获取父类标记在Type上的注解。如果注解标记在父类方法上,子类覆盖的方法无法获取到注解。如果子类实现一个或多个接口,也不会从它实现的接口继承任何注释。
想实现方法上注解的继承,你可以通过反射在继承链上找到方法上的注解,或者Spring也提供了AnnotationUtils用于处理Annotation。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public static <A extends Annotation > A getInheritedAnnotation ( Class<A> annotationClass, AnnotatedElement element) { A annotation = element.getAnnotation(annotationClass); if (annotation == null && element instanceof Method) annotation = getOverriddenAnnotation(annotationClass, (Method) element); return annotation; } private static <A extends Annotation > A getOverriddenAnnotation ( Class<A> annotationClass, Method method) { final Class<?> methodClass = method.getDeclaringClass(); final String name = method.getName(); final Class<?>[] params = method.getParameterTypes(); final Class<?> superclass = methodClass.getSuperclass(); if (superclass != null ) { final A annotation = getOverriddenAnnotationFrom(annotationClass, superclass, name, params); if (annotation != null ) return annotation; } for (final Class<?> intf : methodClass.getInterfaces()) { final A annotation = getOverriddenAnnotationFrom(annotationClass, intf, name, params); if (annotation != null ) return annotation; } return null ; } private static <A extends Annotation > A getOverriddenAnnotationFrom ( Class<A> annotationClass, Class<?> searchClass, String name, Class<?>[] params) { try { final Method method = searchClass.getMethod(name, params); final A annotation = method.getAnnotation(annotationClass); if (annotation != null ) return annotation; return getOverriddenAnnotation(annotationClass, method); } catch (final NoSuchMethodException e) { return null ; } }
@Native
用于表示可从Native方法获取的常量属性。
@Repeatable
表示标记的注释可以多次应用于同一声明或类型使用,即重复注解。
重复注解示例 1 2 3 4 @Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup () { ... }
为了实现重复注解,需要下面两步:
声明一个可重复注解类型 1 2 3 4 5 6 7 8 import java.lang.annotation.Repeatable;@Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth () default "first" ; String dayOfWeek () default "Mon" ; int hour () default 12 ; }
@Repeatable
注解的值是注解容器的类型,java 编译器用它来存储重复注解。
声明该类型注解容器 1 2 3 public @interface Schedules { Schedule[] value(); }
注解容器必须拥有数组类型的变量属性,数组元素类型必须是重复注解的类型。
Java 自身使用的注解 在 java.lang 中使用了下面5个注解:
@Deprecated
@Deprecated
注解表示标记的元素已被弃用,不应再使用。
使用例子:
1 2 3 4 5 6 / ** * @deprecated * 解释为什么它被弃用 * / @Deprecated static void deprecatedMethod(){}
@Override
@Override
注解表示意图覆盖超类中声明的元素。
1 2 3 @Override int overriddenMethod(){}
@SuppressWarnings
@SuppressWarnings
注释告诉编译器压制它将会生成的特定警告。
1 2 3 4 5 6 @SuppressWarnings (“deprecation”)void useDeprecatedMethod(){ objectOne.deprecatedMethod(); }
@SafeVarargs
@SafeVarargs
注解在应用于方法或构造函数时,声明该代码对其参数不执行潜在的不安全操作。
@FunctionalInterface
@FunctionalInterface
注解,在Java SE 8引入,表示该类型声明意在成为功能的接口,由Java语言规范所定义的。
参考资料: