Java Annotation 注解
Annotation 注解
最近工作用到了注解,发现自己对其中一些细节不甚了解,粗度《Java Language Features, 2nd Edition》并记录一下。
Java 注解分为一下几个模块
- 注解是什么
- 如何声明注解
- 如何使用注解
- 元注解是什么&如何使用
- 常用的注解,如@Deprecated、@SupressWarning、@Override、@FunctionalInterface
- Java运行时如何获取注解
- 自定义注解处理
What annotations are
meaning: A note added by way of comment or explaination.
purpose: Document the programs and let the compiler verify the intention of the programmer.
uses: documentation, verification and enforcement by the compiler, the runtime validation, code generation by framework/tools, etc.
How to declare annotations
[modifiers] @ interface {// Annotation type body goes here
}
The @ sign and the interface keyword may be separated by whitespace or they can be placed together. By convention, they are placed together as @interface.
@interface 可以与其他修饰符混在一行,也可单独放一行(推荐)。
注意
-
注解中可声明0至多个元素
element。 -
元素只可为抽象方法。
Although you can declare static and default methods in interface types, they are not allowed in annotation types. static and default methods are meant to contain some logic. Annotations are meant to represent just the values for elements in the annotation type. This is the reason that static and default methods are not allowed in annotation types.
Restrictions on Annotation Types
-
不能继承其他注解。注解隐含继承了Annotation,在运行时Java会创建注解的代理类,可使用
equals()hashCode()toString() -
元素方法不能指定任何参数。Java运行时由代理类自动创建,不得指定参数。
-
注解中方法不能抛异常。异常代表一个data值无效。
-
方法返回值类型:
-
8种基本类型
-
String
-
Class
-
enum type
-
annotation type
-
上述类型的数组
-
-
不能重写Object或Annotation中的方法。
-
注解类型不能是泛型。
Default value of an Annotation Element
[modifiers] @interface { () default ;
}
注意
-
默认值在程序取值时才能读到,而不是编译时。
-
使用时需保证所有字段均有值。
Annotation Type and Its Instances
annotation type 特指注解模式使用。其类型类似与接口。所以类似于接口,也可创建其实例(不推荐)。
How to use annotations
Using Annotations
-
在编译时必须给元素赋值,且必须是编译时常量
compile-time constant,保证其不能为空。@Name(first="Jo" + "hn", last="Ja" + "cobs") # 可以 @Name(first="John", last="Jacobs") # 可以@Name(first="Mr. " + Test.UNKNWON, last=Test.UNKNOWN) # 可以 @Name(first=new String("John"), last="Jacobs") # 不行 # new String("John") 不是编译时的常量,在编译注解时取不到该值。 -
annotation中方法不可抛异常
-
annotation中可用
annotation type,如@Descirption(name=@Name(first="John", last="Jocobs"), version=@Version(..)..) -
List格式
-
如果其中只有一个元素,可省略大括号
-
可传空list,如
@ToDo(item={})
-
No Null in Annotaion
注解中元素不得为null。
Shorthand Annotation Syntax
-
annotation 中所有元素均有默认值,可省略小括号
@Enable -
annotation 只有一个元素,可省略
name=@Company("Abc Inc.") @Reviewer({"张三", "李四"}) -
annotation 只有一个车元素,且为list,初始化时只有一个值,可省略大括号
@Reviewer("张三") -
一些复杂情况
public @interface A {String value();int id() default 10; } // Same as @A(value="Hello", id=10) @A("Hello") public class Test {// Code goes here } // Won't compile. Must use only one value to omit the element name @A("Hello", id=16) public class WontCompile {// Code goes here } // OK. Must use name=value pair when passing more than one value @A(value="Hello", id=16) public class Test {// Code goes here }
Maker Annotation Types
没有声明任何元素的注解。常被注解处理工具用于生成模板代码。
public @interface Marker {// No element declarations
}
@Marker
public class Test {// Code goes here
}
What meta-annotations are and how to use them
Meta-Annotation Types
Target
指定annotation适用范围,默认适用全部。
| Constant Name | Description |
|---|---|
| ANNOTATION_TYPE | Used to annotate another annotation type declaration. This makes the annotationtype a meta-annotation. |
| CONSTRUCTOR | Used to annotate constructors. |
| FIELD | Used to annotate fields and enum constants. |
| LOCAL_VARIABLE | Used to annotate local variables. |
| METHOD | Used to annotate methods. |
| MODULE | Used to annotate modules. It was added in Java 9. |
| PACKAGE | Used to annotate package declarations. |
| PARAMETER | Used to annotate parameters. |
| TYPE | Used to annotate class, interface (including annotation type), or enumdeclarations. |
| TYPE_PARAMETER | Used to annotate type parameters in generic classes, interfaces, methods, etc.It was added in Java 8. |
| TYPE_USE | Used to annotate all uses of types. It was added in Java 8. The annotation can also be used where an annotation with ElementType.TYPE and ElementType.TYPE_ |
| PARAMETER | can be used. It can also be used before constructors, in which case it represents the objects created by the constructor. |
Retention
用于标注注解保留策略。
| RetentionPolicy | Description |
|---|---|
| SOURCE | 仅在源码保留。 |
| CLASS | 编译时保留,Java运行时无权限读取。 |
| RUNTIME | 编译时保留,Java运行时可读取。 |
Inherite
指定annotation可被继承。
Documented
生成Javadoc开关。
Repeatable
since 1.8。可重复注解。
@Version(major=1, minor=1)
@Version(major=1, minor=2)
public class Test {// Code goes here
}
Commonly used annotations that are used to deprecate APIs, to suppress named compile-time warnings, override methods, and declare functional interfaces
Commonly Used Standard Annotations
Deprecated
标记危险方法,常在注释中配合#deprecate使用。
/*** The class consists of static methods that can be used to* copy files and directories.** @deprecated Deprecated since 1.4. Not safe to use. Use the
* java.nio.file.Files class instead. This class
* will be removed in a future release of this library.** @since 1.2*/@Deprecated
public class FileCopier {// No direct instantiation supportedprivate FileCopier() {}/*** Copies the contents of src to dst.* @param src The source file* @param dst The destination file* @return true if the copy is successfully, false otherwise.*/public static boolean copy(File src, File dst) {// More code goes herereturn true;}// More code goes here
}
JDK9添加了 since() forRemoval()
根据 forRemoval()分为两类:
-
false:Ordinary Deprecated -
true:Terminally Deprecated
| API Use-Site | API Declaration Site | ||
|---|---|---|---|
| Not Deprecated | Ordinarily Deprecated | Terminally Deprecated | |
| Not Deprecated | N | OW | RW |
| Ordinarily Deprecated | N | N | RW |
| Terminally Deprecated | N | N | RW |
N = No Warning OW = Ordinary deprecation warning RW = Removal deprecation Warning
Suppressing Warning
用于消除警告。
注意 : 在JDK9之后,需要根据@Deprecated的等级消除。
package com.jdojo.annotation;
public class BoxTest {/*** API: Not deprecated* Use-site: Not deprecated* Deprecation warning: No warning*/public static void m11() {Box.notDeprecated();}/*** API: Ordinarily deprecated* Use-site: Not deprecated* Deprecation warning: No warning*/public static void m12() {Box.deprecatedOrdinarily();}/*** API: Terminally deprecated* Use-site: Not deprecated* Deprecation warning: Removal warning*/public static void m13() {Box.deprecatedTerminally();}/*** API: Not deprecated* Use-site: Ordinarily deprecated* Deprecation warning: No warning* @deprecated Dangerous to use.*/@Deprecated(since="1.1")public static void m21() {Box.notDeprecated();}/*** API: Ordinarily deprecated* Use-site: Ordinarily deprecated* Deprecation warning: No warning* @deprecated Dangerous to use.*/@Deprecated(since="1.1")public static void m22() {Box.deprecatedOrdinarily();}/*** API: Terminally deprecated* Use-site: Ordinarily deprecated* Deprecation warning: Removal warning* @deprecated Dangerous to use.*/@Deprecated(since="1.1")public static void m23() {Box.deprecatedTerminally();}/*** API: Not deprecated* Use-site: Terminally deprecated* Deprecation warning: No warning* @deprecated Going away.*/@Deprecated(since="1.1", forRemoval=true)public static void m31() {Box.notDeprecated();}/*** API: Ordinarily deprecated* Use-site: Terminally deprecated* Deprecation warning: No warning* @deprecated Going away.*/@Deprecated(since="1.1", forRemoval=true)public static void m32() {Box.deprecatedOrdinarily();}/*** API: Terminally deprecated* Use-site: Terminally deprecated* Deprecation warning: Removal warning* @deprecated Going away.*/@Deprecated(since="1.1", forRemoval=true)public static void m33() {Box.deprecatedTerminally();}/*** API: Ordinarily and Terminally deprecated* Use-site: Not deprecated* Deprecation warning: Ordinary and removal warnings*/public static void m41() {Box.deprecatedOrdinarily();Box.deprecatedTerminally();}/*** API: Ordinarily and Terminally deprecated* Use-site: Not deprecated* Deprecation warning: Ordinary warnings*/@SuppressWarnings("deprecation")public static void m42() {Box.deprecatedOrdinarily();Box.deprecatedTerminally();}/*** API: Ordinarily and Terminally deprecated* Use-site: Not deprecated* Deprecation warning: Removal warnings*/@SuppressWarnings("removal")public static void m43() {Box.deprecatedOrdinarily();Box.deprecatedTerminally();}/*** API: Ordinarily and Terminally deprecated* Use-site: Not deprecated* Deprecation warning: Removal warnings*/@SuppressWarnings({"deprecation", "removal"})public static void m44() {Box.deprecatedOrdinarily();Box.deprecatedTerminally();}
}
Override
重写方法。需保证方法名、参数一致。
Functional Interface
仅包含一个元素的注解。
@FunctionalInterface
public interface Runner {void run();
}
Annotation Packages
对包加注解。
// package-info.java
@com.jdojo.myannotations.Author("John Jacobs")
@Reviewer("Wally Inman")
package com.jdojo.annotation;
import com.jdojo.myannotations.Reviewer;
Annotation Modules
对模块加注解。
@Deprecated(since="1.2", forRemoval=true)
@SuppressWarnings("unchecked")
module com.jdojo.myModule {// Module statements go here
}
How to access annotations at runtime
反射获取注解。
注意 : 需在通过Retention声明RUNTIME类型。
Class cls = Test.class;
Annotation[] allAnns = cls.getAnnotations();
Version v = cls.getAnnotation(Version.class);
How to process annotations in source code
在编译时执行可生成代码或配置文件。
-
An annotation processor is an object of a class, which implements the Processor interface.
-
The annotation processor object is instantiated by the compiler using a no-args constructor.
-
在process方法中处理。annotations获取所有注解;roundEv根据注解获取所有的值。
// VersionProcessor.java
package com.jdojo.annotation.processor;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
@SupportedAnnotationTypes({"com.jdojo.annotation.Version"})
@SupportedSourceVersion(SourceVersion.RELEASE_9)
public class VersionProcessor extends AbstractProcessor {// A no-args constructor is required for an annotation processorpublic VersionProcessor() {}@Overridepublic boolean process(Set extends TypeElement> annotations, RoundEnvironmentroundEnv) {// Process all annotationsfor (TypeElement currentAnnotation: annotations) {Name qualifiedName = currentAnnotation.getQualifiedName();// check if it is a Version annotationif (qualifiedName.contentEquals("com.jdojo.annotation.Version" )) {// Look at all elements that have Version annotationsSet extends Element> annotatedElements;annotatedElements = roundEnv.getElementsAnnotatedWith(currentAnnotation);for (Element element: annotatedElements) {Version v = element.getAnnotation(Version.class);int major = v.major();int minor = v.minor();if (major < 0 || minor < 0) {// Print the error messageString errorMsg = "Version cannot be negative." +" major=" + major +" minor=" + minor;Messager messager = this.processingEnv.getMessager();messager.printMessage(Kind.ERROR, errorMsg, element);}}}}return true;}
}
PS: csdn的md格式跟typora还有点不一样,弄得我又调整了一下格式,吐槽一下。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
