最后有一點(diǎn)需要注意的是:
當(dāng)我們使用@interface關(guān)鍵字定義一個(gè)注解時(shí),該注解隱含地繼承了java.lang.annotation.Annotation接口;如果我們定義了一個(gè)接口,并且讓該接口繼承自Annotation,那么我們所定義的接口依然還是接口而不是注解;Annotation本身是接口而不是注解??梢耘cEnum類比。
第2集
本集主要講述@Retention及@Target2個(gè)注解,順帶提一下@Documented這個(gè)注解
1.關(guān)于@Retention這個(gè)注解
Retention翻譯成中文是“保留”的意思,RetentionPolicy是“保留策略”。
簡要描述:指示注解類型的注解要保留多久。如果注解類型聲明中不存在 Retention 注解,則保留策略默認(rèn)為 RetentionPolicy.CLASS。
每一個(gè)Retention都要給他一個(gè)RetentionType,RetentionType是一個(gè)枚舉類型(具體可以查看API文檔),它有3種取值:SOURCE,CLASS,RUNTIME,區(qū)別如下:
(a)SOURCE:表示該注解只會(huì)存在于JAVA源文件中,不會(huì)編譯到class文件里面去,更不會(huì)在運(yùn)行期通過反射的方式獲 取到。
(b)CLASS:表示該注解會(huì)隨著JAVA源代碼一起編譯到class文件里面去,但不會(huì)在運(yùn)行期通過反射的方式獲取到。
(c)RUNTIME:表示該注解會(huì)隨著JAVA源代碼一起編譯到class文件里面去,并且會(huì)在運(yùn)行期通過反射的方式獲取到。
請看一個(gè)示例:
首先定義一個(gè)注解:
- 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;
//注解也可以修飾注解,該注解修飾下面自定義的注解,通過設(shè)定
//RetentionPolicy的值為RUNTIME表示該自定義的注解會(huì)被編
//譯到CLASS文件當(dāng)中,而且可以在運(yùn)行期通過反射的方式獲取到(具體請查看一遍API文檔,很有必要?。?
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{
String hello() default "shengsiyuan";
String world();
}
然后定義一個(gè)類,用這個(gè)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
{
//一個(gè)方法可以被多個(gè)注解所修飾。
@MyAnnotation(hello = "tianjin", world = "shangdi")
@Deprecated
@SuppressWarnings("unchecked")
public void output()
{
System.out.println("output something!");
}
}
接著定義一個(gè)類,并通過反射相關(guān)API去獲得自定義注解的相關(guān)信息
- 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[]{});
//能夠進(jìn)入到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);
}
//只會(huì)得到Myannotation和Deprecated兩個(gè)Annotation,因?yàn)橹挥羞@兩個(gè)Annotation的RetentionPolicy
//的值為Runtime,只有RetentionPolicy的值為Runtime才會(huì)在運(yùn)行期通過反射相關(guān)API拿到Annotation的相關(guān)信息。
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations)
{
System.out.println(annotation.annotationType().getName());
}
}
}
2.關(guān)于@Target這個(gè)注解(建議去讀一讀API文檔,介紹的很詳細(xì))
簡要描述:指示注解類型所適用的程序元素的種類。如果注解類型聲明中不存在 Target 元注解,則聲明的類型可以用在任一程序元素上。
每一個(gè)Target都要給他一個(gè)ElementType,ElementType是一個(gè)枚舉類型(具體可以查看API文檔),它有8種取值:SOURCE,CLASS,RUNTIME,區(qū)別如下:
(a)ANNOTATION_TYPE:表示該注解可以去修飾另外一個(gè)注解
(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();
}
接著定義一個(gè)類:
- 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");
}
}
當(dāng)把該自定義的注解放到方法上面后編譯器不報(bào)錯(cuò)時(shí),說明我們的實(shí)驗(yàn)是成功的(不需要寫main方法進(jìn)行測試)
對(duì)以上2個(gè)注解的總結(jié):Retention與Target都是注解,Retention與RetentionPolicy搭配,Target與ElementType搭配。
3.關(guān)于@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 //當(dāng)一個(gè)注解被@Documented 修飾后表示被該注解修飾的對(duì)象(類或方法或其他)在生成JAVA DOC文檔時(shí),該注解會(huì)被加到修飾的對(duì)象的上面
public @interface DocumentedAnnotation
{
String hello();
}
然后用該注解去修飾某個(gè)方法
- 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");
}
}
當(dāng)對(duì)DocumentedTest所在的包或工程生成JAVA DOC文檔的時(shí)候,會(huì)發(fā)現(xiàn)自定義的注解會(huì)出現(xiàn)在method方法的上面