java基礎解析系列(六)---注解原理及使用
- java基礎解析系列(一)---String、StringBuffer、StringBuilder
- java基礎解析系列(二)---Integer緩存及裝箱拆箱
- java基礎解析系列(三)---HashMap原理
- java基礎解析系列(四)---LinkedHashMap的原理及LRU算法的實現
- java基礎解析系列(五)---HashMap並發下的問題以及HashTable和CurrentHashMap的區別
- 這是我的博客目錄,歡迎閱讀
先來一個例子
class Father
{
public void f()
{}
}
public class Son extends Father{
@Override
public void f()
{}
}
- 當子類重寫父類的方法的時候,上面會出現一個
@Override
,這就是一個注解
@Controller
public class StudentController {
- 框架中的
@Controller
也是一個注解
什么是注解
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
- 注解是一個接口
- 從某方面看,注解的作用就像修飾符(public,final,static)一樣
- 程序可以通過反射來獲取指定程序元素的Annotion,然后通過Annotion來獲取注解里面的元數據。
注解的種類
- JDK內置系統注解
- 元注解,用於'修飾'注解
- 自定義注解
JDK內置系統注解
@Override
- 上面的例子已經展示,這個注解的作用是用於修飾覆蓋了父類的方法
@Deprecated
- 這個注解是用來修飾已經過時的方法
- 可以看到當方法用@Deprecated修飾,然后使用這個方法的時候,編譯器會提醒這個方法已經過時
@SuppressWarnnings
- 用於忽略編譯器警告信息,告訴編譯器停止對此方法的警告。
元注解
@Target
- 作用:被描述的注解可以用在什么地方
- 參數值
ElementType | 含義 |
---|---|
ElementType | 含義 |
ANNOTATION_TYPE | 注解類型聲明 |
CONSTRUCTOR | 構造方法聲明 |
FIELD | 字段聲明(包括枚舉常量) |
LOCAL_VARIABLE | 局部變量聲明 |
METHOD | 方法聲明 |
PACKAGE | 包聲明 |
PARAMETER | 參數聲明 |
TYPE | 類、接口(包括注解類型)或枚舉聲明 |
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Target(ElementType.FIELD)
public @interface MyAnnotation {
}
- 上面是自定義的一個注解,用了一個@Target來修飾,表明這個自定義注解可以用來修飾域
@Retention
- 作用:指示注釋類型的注釋要保留多久
- 參數值
RetentionPoicy | 意義 |
---|---|
SOURCE | 源文件中保留,比如@Override,用於與編譯器交互 |
CLASS | source,Class文件保留,用於編譯時生成額外的文件 |
RUNTIME | sorce,class文件,運行時保留 |
@Documented
- 作用:指示某一類型的注釋將通過 javadoc 和類似的默認工具進行文檔化
- 被@Documented修飾的注解會生成到javadoc中
import java.lang.annotation.Documented;
@Documented
public @interface Demo
{
}
- 打開cmd,然后執行javadoc Demo.java,然后可以看到這個注解生成到了javadoc
@Inherited
- 作用:指示注釋類型被自動繼承。可以讓子類對象使用getAnnotations()獲取父類@Inherited修飾的注解。
@Inherited
@Retention( RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String msg() default "jiajun";
}
@MyAnnotation
class Father
{
}
class son extends Father{
}
public class Demo6
{
public static void main(String[] args) {
Father f=new son();
System.out.println(Arrays.toString(f.getClass().getAnnotations()));
}
}
//輸出:[@MyAnnotation(msg=jiajun)]
自定義注解
格式
- public @interface 注解名 {定義體}
@Retention源碼
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
- 可以看到注解方法返回值是RetentionPolicy枚舉類型
使用
- 用@interface(區別於interface)來聲明一個注解
- 使用@interface定義注解的時候,自動繼承了Annotation接口
- 用元注解修飾自定義注解
- 定義體里面可以定義一些參數成員,default設置默認參數值
- 使用注解的時候,傳值方式(msg=""),當參數名是value的時候,可以直接用("666")的形式傳值。
- 當沒有傳值的時候,
@MyAnnotation()
,獲取到的參數值是默認值
實驗
@Retention( RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String msg() default "jiajun";
}
@MyAnnotation(msg="666")
class Test1
{}
public class Test2 {
public static void main(String[] args) {
Test1 t=new Test1();
Class c=t.getClass();
MyAnnotation ma = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
System.out.println(ma.msg());
}
}
- 自定義了一個MyAnnotation注解,用Retention注解聲明注解的生命周期,和Target修飾該注解的修飾范圍
- Test1類用自定義的注解修飾,通過Class獲取相關信息。當Rention修飾的不是RUNTIME的時候,不能獲得相關信息
訪問注解
訪問類注解
@Retention( RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String name() default "jiajun";
}
@MyAnnotation(name="jiajun")
public class Test {
}
public static void main(String[] args) {
Class clazz = Test.class;
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
}
}
}
訪問方法注解
@Retention( RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String name() default "jiajun";
}
public class Test {
@MyAnnotation(name="jiajun")
public void doSomething(){}
}
public class Demo {
public static void main(String[] args) {
Class clazz=Test.class;
Method[] methods=clazz.getMethods();
for(Method method :methods)
{
if(method.getName()=="doSomething")
{
Annotation annotation = method.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
}
}
}
}
}
訪問參數注解
@Retention( RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface MyAnnotation {
String name() default "jiajun";
}
public class Test {
public static void doSomething(
@MyAnnotation(name="jiajun") String parameter){
}
}
public class Demo {
public static void main(String[] args) {
Class clazz=Test.class;
Method[] methods=clazz.getMethods();
for(Method method :methods)
{
if(method.getName()=="doSomething")
{
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();
int i=0;
for(Annotation[] annotations : parameterAnnotations){
Class parameterType = parameterTypes[i++];
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("param: " + parameterType.getName());
System.out.println("name : " + myAnnotation.name());
}
}
}
}
}
}
}
- 每個方法有n個參數,每個參數包含一個注解數組,因此getParameterAnnotations()返回的是一個二維數組
我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鍾、半秒鍾,哪怕說一句話有點道理,引發自己內心的感觸,這就是我最大的價值。(這是我喜歡的一句話,也是我寫博客的初衷)
作者:jiajun 出處: http://www.cnblogs.com/-new/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。如果覺得還有幫助的話,可以點一下右下角的【推薦】,希望能夠持續的為大家帶來好的技術文章!想跟我一起進步么?那就【關注】我吧。