第 17章
Annotation
– Annotation
– meta-annotation
限定 Override父类方法 @Override
对编译程序说明某个方法必须是重新定义父类别中的方法
public class CustomClass {
@Override
public StringToString() {
return "customObject";
}
}
CustomClass.java:4,method does not override a
method from its superclass
@Override
^1 error
限定 Override父类方法 @Override
java.lang.Override是个 Marker annotation
用于标示的 Annotation,Annotation名称本身即表示了要给工具程序的信息标示方法為 Deprecated @Deprectated
对编译程序说明某个方法已经不建议使用
public class Something {
@Deprecated public Something getSomething() {
return new Something();
}
}
Something some = new Something();
//呼叫被 @Deprecated标示的方法
some.getSomething();
javac -Xlint:deprecation -d,SomethingDemo.java
SomethingDemo.java:6,warning,[deprecation] getSomething() in
onlyfun.caterpillar.Something has been deprecated
some.getSomething();
^1 warning
标示方法为 Deprecated @Deprectated
java.lang.Deprecated也是個 Marker
annotation
Deprecated这个名称在告知编译程序,被
@Deprecated标示的方法是一个不建议被使用的方法抑制编译程序警讯 @SuppressWarnings
对编译程序说明某个方法中若有警示讯息,
则加以抑制
import java.util.*;
public class SomeClass {
public void doSomething() {
Map map = new HashMap();
map.put("some","thing");
}
}
Note,SomeClass.java uses unchecked or unsafe operations.
Note,Recompile with -Xlint:unchecked for details.
javac-Xlint:unchecked -d,SomeClass.java
SomeClass.java:8,warning,[unchecked] unchecked call to put(K,V)
as a member of the raw type java.util.Map
map.put("some","thing");
^1 warning
抑制编译程序警讯 @SuppressWarnings
import java.util.*;
public class SomeClass2 {
@SuppressWarnings(value={"unchecked"})
public void doSomething() {
Map map = new HashMap();
map.put("some","thing");
}
}
@SuppressWarnings(value={"unchecked","deprecation"})
自定义 Annotation型态
定义 Marker Annotation,也就是 Annotation
名称本身即提供信息
对于程序分析工具来说,主要是检查是否有 MarkerAnnotation的出现,并作出对应的动作
public@interface Debug {}
public class SomeObject {
@Debug
public void doSomething() {
//,...
}
}
自定义 Annotation型态
Single-value annotation
public@interface UnitTest {
String value();
}
public class MathTool {
@UnitTest("GCD")
public static int gcdOf(int num1,int num2) {
//,...
}
}
自定义 Annotation型态
public@interface FunctionTest {
String[] value();
}
@FunctionTest({"method1","method2"})
简便形式
详细形式
value成员设定默认值,用 "default"关键词
@FunctionTest(value={"method1","method2"})
public @interface UnitTest2 {
String value() default "noMethod";
}
自定义 Annotation型态
public @interface Process {
public enum Current {NONE,REQUIRE,ANALYSIS,DESIGN,SYSTEM};
Current current() default Current.NONE;
String tester();
boolean ok();
}
public class Application {
@Process(
current =Process.Current.ANALYSIS,
tester = "Justin Lin",
ok = true
)
public void doSomething() {
//,...
}
}
自定义 Annotation型态
使用 @interface自行定义 Annotation型态时,
实际上是自动继承了
java.lang.annotation.Annotation界面
由编译程序自动为您完成其它产生的细节
在定义 Annotation型态时,不能继承其它的
Annotation型态或是接口自定义 Annotation型态
定义 Annotation型态时也可以使用套件机制来管理类别
import onlyfun.caterpillar.Debug;
public class Test {
@Debug
public void doTest() {
}
}
public class Test {
@onlyfun.caterpillar.Debug
public void doTest() {
}
}
告知编译程序如何处理 @Retention
java.lang.annotation.Retention型态可以在您定义 Annotation型态时,指示编译程序该如何对待您的自定义的 Annotation型态
预设上编译程序会将 Annotation信息留在,class档案中,但不被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息告知编译程序如何处理 @Retention
在使用 Retention型态时,需要提供
java.lang.annotation.RetentionPolicy的列举型态
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE,//编译程序处理完 Annotation信息后就没事了
CLASS,//编译程序将 Annotation储存于 class档中,预设
RUNTIME //编译程序将 Annotation储存于 class檔中,可由 VM读入
}
告知编译程序如何处理 @Retention
RetentionPolicy为 SOURCE的例子是
@SuppressWarnings
仅在编译时期告知编译程序来抑制警讯,所以不必将这个信息储存于,class档案
RetentionPolicy为 RUNTIME的时机,可以像是您使用 Java设计一个程序代码分析工具,您必须让
VM能读出 Annotation信息,以便在分析程序时使用
搭配反射( Reflection)机制,就可以达到这个目的告知编译程序如何处理 @Retention
java.lang.reflect.AnnotatedElement界面
Class,Constructor,Field,Method、
Package等类别,都实作了
AnnotatedElement界面
public Annotation getAnnotation(Class annotationType);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
public boolean isAnnotationPresent(Class annotationType);
告知编译程序如何处理 @Retention
定义 Annotation时必须设定 RetentionPolicy
为 RUNTIME,也就是可以在 VM中读取
Annotation信息
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnnotation {
String value();
String name();
}
public class SomeClass3 {
@SomeAnnotation(
value = "annotation value1",
name = "annotation name1"
)
public void doSomething() { }
}
告知编译程序如何处理 @Retention
Class<SomeClass3> c = SomeClass3.class;
//因为 SomeAnnotation标示于 doSomething()方法上
//所以要取得 doSomething()方法的 Method实例
Method method = c.getMethod("doSomething");
//如果 SomeAnnotation存在的话
if(method.isAnnotationPresent(SomeAnnotation.class)) {
System.out.println("找到 @SomeAnnotation");
//取得 SomeAnnotation
SomeAnnotation annotation =
method.getAnnotation(SomeAnnotation.class);
//取得 value成员值
System.out.println("\tvalue = " + annotation.value());
//取得 name成员值
System.out.println("\tname = " + annotation.name());
}
告知编译程序如何处理 @Retention
else {
System.out.println("找不到 @SomeAnnotation");
}
//取得 doSomething()方法上所有的 Annotation
Annotation[] annotations = method.getAnnotations();
//显示 Annotation名称
for(Annotation annotation,annotations) {
System.out.println("Annotation名称," +
annotation.annotationType().getName());
}
找到 @SomeAnnotation
value = annotation value1
name = annotation name1
Annotation名称,onlyfun.caterpillar.SomeAnnotation
限定 annotation使用对象 @Target
使用 java.lang.annotation.Target可以定义其适用之时机
在定义时要指定
java.lang.annotation.ElementType的列举值之一限定 annotation使用对象 @Target
package java.lang.annotation;
public enum ElementType {
TYPE,//适用 class,interface,enum
FIELD,//适用 field
METHOD,//适用 method
PARAMETER,//适用 method上之 parameter
CONSTRUCTOR,//适用 constructor
LOCAL_VARIABLE,//适用局部变量
ANNOTATION_TYPE,//适用 annotation型态
PACKAGE //适用 package
}
限定 annotation使用对象 @Target
限定它只能适用于建构方法与方法成员
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
public @interface MethodAnnotation {}
限定 annotation使用对象 @Target
尝试将 MethodAnnotation标示于类别之上
@onlyfun.caterpillar.MethodAnnotation
public class SomeoneClass {
public void doSomething() {
//,...
}
}
SomeObject.java:1,annotation type not applicable to this
kind of declaration
@onlyfun.caterpillar.MethodAnnotation^1 error
要求为 API文件 @Documented
想要在使用者制作 JavaDoc文件的同时,也一并将 Annotation的讯息加入至 API文件中
使用 java.lang.annotation.Documented
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface TwoAnnotation {}
子类是否继承父 類 @Inherited
预设上父类别中的 Annotation并不会被继承至子类别中
可以在定义 Annotation型态时加上
java.lang.annotation.Inherited型态的
Annotation
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ThreeAnnotation {
String value();
String name();
}