最后有一點需要注意的是:
當我們使用@interface關鍵字定義一個注解時,該注解隱含地繼承了java.lang.annotation.Annotation接口,;如果我們定義了一個接口,,并且讓該接口繼承自Annotation,那么我們所定義的接口依然還是接口而不是注解,;Annotation本身是接口而不是注解,。可以與Enum類比,。
第2集
本集主要講述@Retention及@Target2個注解,,順帶提一下@Documented這個注解
1.關于@Retention這個注解
Retention翻譯成中文是“保留”的意思,RetentionPolicy是“保留策略”,。
簡要描述:指示注解類型的注解要保留多久,。如果注解類型聲明中不存在 Retention 注解,則保留策略默認為 RetentionPolicy.CLASS,。
每一個Retention都要給他一個RetentionType,RetentionType是一個枚舉類型(具體可以查看API文檔),,它有3種取值:SOURCE,CLASS,RUNTIME,區(qū)別如下:
(a)SOURCE:表示該注解只會存在于JAVA源文件中,不會編譯到class文件里面去,,更不會在運行期通過反射的方式獲 取到,。
(b)CLASS:表示該注解會隨著JAVA源代碼一起編譯到class文件里面去,但不會在運行期通過反射的方式獲取到,。
(c)RUNTIME:表示該注解會隨著JAVA源代碼一起編譯到class文件里面去,,并且會在運行期通過反射的方式獲取到。
請看一個示例:
首先定義一個注解:
- package com.shengsiyuan.annotation;
-
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
-
-
-
-
-
- @Retention(RetentionPolicy.RUNTIME)
- public @interface MyAnnotation
- {
- String hello() default "shengsiyuan";
-
- String world();
- }
package com.shengsiyuan.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//注解也可以修飾注解,該注解修飾下面自定義的注解,,通過設定
//RetentionPolicy的值為RUNTIME表示該自定義的注解會被編
//譯到CLASS文件當中,,而且可以在運行期通過反射的方式獲取到(具體請查看一遍API文檔,,很有必要?。?
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{
String hello() default "shengsiyuan";
String world();
}
然后定義一個類,,用這個Annotation去修飾
- package com.shengsiyuan.annotation;
-
- @MyAnnotation(hello = "beijing", world = "shanghai")
- public class MyTest
- {
-
- @MyAnnotation(hello = "tianjin", world = "shangdi")
- @Deprecated
- @SuppressWarnings("unchecked")
- public void output()
- {
- System.out.println("output something!");
- }
- }
package com.shengsiyuan.annotation;
@MyAnnotation(hello = "beijing", world = "shanghai")
public class MyTest
{
//一個方法可以被多個注解所修飾,。
@MyAnnotation(hello = "tianjin", world = "shangdi")
@Deprecated
@SuppressWarnings("unchecked")
public void output()
{
System.out.println("output something!");
}
}
接著定義一個類,,并通過反射相關API去獲得自定義注解的相關信息
- package com.shengsiyuan.annotation;
-
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Method;
-
-
- public class MyReflection
- {
- public static void main(String[] args) throws Exception
- {
- MyTest myTest = new MyTest();
-
- Class<MyTest> c = MyTest.class;
-
- Method method = c.getMethod("output", new Class[]{});
-
-
- if(method.isAnnotationPresent(MyAnnotation.class))
- {
- method.invoke(myTest, new Object[]{});
-
- MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
-
- String hello = myAnnotation.hello();
- String world = myAnnotation.world();
-
- System.out.println(hello + ", " + world);
- }
-
-
-
- Annotation[] annotations = method.getAnnotations();
-
- for(Annotation annotation : annotations)
- {
- System.out.println(annotation.annotationType().getName());
- }
- }
- }
package com.shengsiyuan.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
//該類拿到修飾MyTest里方法的Annotation
public class MyReflection
{
public static void main(String[] args) throws Exception
{
MyTest myTest = new MyTest();
Class<MyTest> c = MyTest.class;
Method method = c.getMethod("output", new Class[]{});
//能夠進入到if語句里面來說明MyAnnotation的RetentionPolicy的值為Runtime(為什么請查API文檔!)
if(method.isAnnotationPresent(MyAnnotation.class))
{
method.invoke(myTest, new Object[]{});
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String hello = myAnnotation.hello();
String world = myAnnotation.world();
System.out.println(hello + ", " + world);
}
//只會得到Myannotation和Deprecated兩個Annotation,因為只有這兩個Annotation的RetentionPolicy
//的值為Runtime,只有RetentionPolicy的值為Runtime才會在運行期通過反射相關API拿到Annotation的相關信息,。
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations)
{
System.out.println(annotation.annotationType().getName());
}
}
}
2.關于@Target這個注解(建議去讀一讀API文檔,,介紹的很詳細)
簡要描述:指示注解類型所適用的程序元素的種類。如果注解類型聲明中不存在 Target 元注解,,則聲明的類型可以用在任一程序元素上,。
每一個Target都要給他一個ElementType,ElementType是一個枚舉類型(具體可以查看API文檔),它有8種取值:SOURCE,CLASS,RUNTIME,區(qū)別如下:
(a)ANNOTATION_TYPE:表示該注解可以去修飾另外一個注解
(b)COUNSTRUCTOR:表示該注解可以修飾構(gòu)造方法
(c)FIELD:表示該注解可以修飾成員變量
(d)LOCAL_VARIABLE:表示該注解可以修飾局部變量
(e)METHOD:表示該注解可以修飾普通方法
(f)PACKAGE:表示該注解可以修飾包
(g)PARAMETER:表示該注解可以修飾方法參數(shù)
(h)TYPE:表示該注解可以修飾類,、接口(包括注解類型)或枚舉聲明
請看示例:
- package com.shengsiyuan.annotation;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Target;
-
- @Target(ElementType.METHOD)
- public @interface MyTarget
- {
- String value();
- }
package com.shengsiyuan.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)//表示該自定義注解只能用于修飾方法
public @interface MyTarget
{
String value();
}
接著定義一個類:
- package com.shengsiyuan.annotation;
-
- public class MyTargetTest
- {
- @MyTarget("hello")
- public void doSomething()
- {
- System.out.println("hello world");
- }
- }
package com.shengsiyuan.annotation;
public class MyTargetTest
{
@MyTarget("hello")
public void doSomething()
{
System.out.println("hello world");
}
}
當把該自定義的注解放到方法上面后編譯器不報錯時,,說明我們的實驗是成功的(不需要寫main方法進行測試)
對以上2個注解的總結(jié):Retention與Target都是注解,Retention與RetentionPolicy搭配,,Target與ElementType搭配,。
3.關于@Documented(了解就行)
不多做描述,請看示例:
- package com.shengsiyuan.annotation;
-
- import java.lang.annotation.Documented;
-
- @Documented
- public @interface DocumentedAnnotation
- {
- String hello();
- }
package com.shengsiyuan.annotation;
import java.lang.annotation.Documented;
@Documented //當一個注解被@Documented 修飾后表示被該注解修飾的對象(類或方法或其他)在生成JAVA DOC文檔時,,該注解會被加到修飾的對象的上面
public @interface DocumentedAnnotation
{
String hello();
}
然后用該注解去修飾某個方法
- package com.shengsiyuan.annotation;
-
- public class DocumentedTest
- {
- @DocumentedAnnotation(hello = "welcome")
- public void method()
- {
- System.out.println("hello world");
- }
- }
package com.shengsiyuan.annotation;
public class DocumentedTest
{
@DocumentedAnnotation(hello = "welcome")
public void method()
{
System.out.println("hello world");
}
}
當對DocumentedTest所在的包或工程生成JAVA DOC文檔的時候,會發(fā)現(xiàn)自定義的注解會出現(xiàn)在method方法的上面