Java的注解有哪些

本篇內(nèi)容主要講解“Java的注解有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Java的注解有哪些”吧!

目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁空間、綿陽服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、德興網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

一、什么是注解

我們大家都知道Java代碼中使用注釋是為了向以后閱讀這份代碼的人解釋說明一些事情,注解是注釋的升級版,它可以向編譯器、虛擬機等解釋說明一些事情。比如我們非常熟悉的@Override就是一種元注解,它的作用是告訴編譯器它所注解的方法是重寫父類的方法,這樣編譯器就會去檢查父類是否存在這個方法,以及這個方法的簽名與父類是否相同。

也就是說,注解是描述Java代碼的代碼,它能夠被編譯器解析,注解處理工具在運行時也能夠解析注解。我們在Java源文件中使用注釋,是為了以后我們或他人再來讀這段代碼時,能夠更好地理解它。Javadoc工具可以解析我們在源代碼中為類、方法、變量等添加的描述信息,并根據(jù)這些描述信息自動生成一個HTML文檔,這些自動生成的文檔即可作為API幫助文檔。只要我們?yōu)轭悺⒎椒ǖ忍砑拥拿枋鲂畔⒎螶avadoc要求的語法,我們就能夠使用Javadoc工具根據(jù)我們的描述信息自動生成一個幫助文檔。而注解比java注釋和Javadoc要強大得多,它們?nèi)咧g的重大的區(qū)別在于,Java注釋和Javadoc描述所發(fā)揮的作用僅僅到編譯時就止步了,而注解直到運行時都能夠發(fā)揮作用。

我們知道,使用“transient”關(guān)鍵字可以告訴編譯器這個域不可序列化。相比于用”transient“這樣的關(guān)鍵字修飾一個屬性,注解為我們提供了為類/方法/屬性/變量添加描述信息的更通用的方式,而這些描述信息對于開發(fā)者、自動化工具、Java編譯器和Java運行時來說都是有意義的,也就是說他們都能“讀懂”注解信息?!眛ransient“關(guān)鍵字是一個修飾符,而注解也是一種修飾符。除了傳遞信息,我們也可以使用注解生成代碼。我們可以使用注解,然后讓注解解析工具來解析它們,以此來生成一些”模板化“的代碼。比如Hibernate、Spring、Axis這些框架大量使用了注解,來避免一些重復(fù)的工作。

二、元注解

    元注解即用來描述注解的注解,比如以下代碼中我們使用“@Target”元注解來說明MethodInfo這個注解只能應(yīng)用于對方法進(jìn)行注解:

1
2
3
4
@Target(ElementType.METHOD)
public @interface MethodInfo {
    ...
}

下面我們來具體介紹一下幾種元注解。

1. Documented

當(dāng)一個注解類型被@Documented元注解所描述時,那么無論在哪里使用這個注解,都會被Javadoc工具文檔化。我們來看一下它的定義:

1
2
3
4
5
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

我們從以上代碼中可以看到,定義注解使用@interface關(guān)鍵字,這就好比我們定義類時使用class關(guān)鍵字,定義接口時使用interface關(guān)鍵字一樣,注解也是一種類型。這個元注解被@Documented修飾,表示它本身也會被文檔化。@Retention元注解的值RetentionPolicy.RUNTIME表示@Documented這個注解能保留到運行時;@Target元注解的值ElementType.ANNOTATION_TYPE表示@Documented這個注解只能夠用來描述注解類型。

2. Inherited

表明被修飾的注解類型是自動繼承的。具體解釋如下:若一個注解類型被Inherited元注解所修飾,則當(dāng)用戶在一個類聲明中查詢該注解類型時,若發(fā)現(xiàn)這個類聲明中不包含這個注解類型,則會自動在這個類的父類中查詢相應(yīng)的注解類型,這個過程會被重復(fù),直到該注解類型被找到或是查找完了Object類還未找到。這個元注解的定義如下:

1
2
3
4
5
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

我們可以看到這個元注解類型被@Documented所注解,能夠保留到運行時,只能用來描述注解類型。

3. Retention

我們在上面已經(jīng)見到個這個元注解,它表示一個注解類型會被保留到什么時候,比如以下代碼表示Developer注解會被保留到運行時:

1
2
3
4
@Retention(RetentionPolicy.RUNTIME)
public @interface Developer {
    String value();
}

@Retention元注解的定義如下:

1
2
3
4
5
6
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

我們在使用@Retention時,后面括號里的內(nèi)容即表示他的取值,從以上定義我們可以看到,取值的類型為RetentionPolicy,這是一個枚舉類型,它可以取以下值:

  • SOURCE:表示在編譯時這個注解會被移除,不會包含在編譯后產(chǎn)生的class文件中;

  • CLASS:表示這個注解會被包含在class文件中,但在運行時會被移除;

  • RUNTIME:表示這個注解會被保留到運行時,在運行時可以JVM訪問到,我們可以在運行時通過反射解析這個注解。

4. Target

這個元注解說明了被修飾的注解的應(yīng)用范圍,也就是被修飾的注解可以用來注解哪些程序元素,它的定義如下:

1
2
3
4
5
6
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

從以上定義我們可以看到它也會保留到運行時,而且它的取值是為ElementType[]類型(一個數(shù)組,意思是可以指定多個值),ElementType是一個枚舉類型,它可以取以下值:

  •  TYPE:表示可以用來注解類、接口、注解類型或枚舉類型;

  • PACKAGE:可以用來注解包;

  • PARAMETER:可以用來注解參數(shù);

  • ANNOTATION_TYPE:可以用來注解 注解類型;

  • METHOD:可以用來注解方法;

  • FIELD:可以用來注解屬性(包括枚舉常量);

  • CONSTRUCTOR:可以用來注解構(gòu)造器;

  • LOCAL_VARIABLE:可用來注解局部變量。

三、常見內(nèi)建注解

Java本身內(nèi)建了一些注解,下面我們來介紹一下我們在日常開發(fā)中比較常見的注解:@Override、@Deprecated、@SuppressWarnings。相信我們大家或多或少都使用過這三個注解,下面我們一起再重新認(rèn)識一下它們。

1. @Override注解

我們先來看一下這個注解類型的定義:

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

從它的定義我們可以看到,這個注解可以被用來修飾方法,并且它只在編譯時有效,在編譯后的class文件中便不再存在。這個注解的作用我們大家都不陌生,那就是告訴編譯器被修飾的方法是重寫的父類的中的相同簽名的方法,編譯器會對此做出檢查,若發(fā)現(xiàn)父類中不存在這個方法或是存在的方法簽名不同,則會報錯。

2. @Deprecated

這個注解的定義如下:

1
2
3
4
5
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

從它的定義我們可以知道,它會被文檔化,能夠保留到運行時,能夠修飾構(gòu)造方法、屬性、局部變量、方法、包、參數(shù)、類型。這個注解的作用是告訴編譯器被修飾的程序元素已被“廢棄”,不再建議用戶使用。

3. @SuppressWarnings

這個注解我們也比較常用到,先來看下它的定義:

1
2
3
4
5
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

它能夠修飾的程序元素包括類型、屬性、方法、參數(shù)、構(gòu)造器、局部變量,只能存活在源碼時,取值為String[]。它的作用是告訴編譯器忽略指定的警告信息,它可以取的值如下所示:

  • deprecation:忽略使用了廢棄的類或方法時的警告;

  • unchecked:執(zhí)行了未檢查的轉(zhuǎn)換;

  • fallthrough:swich語句款中case忘加break從而直接“落入”下一個case;

  • path:類路徑或原文件路徑等不存在;

  • serial:可序列化的類缺少serialVersionUID;

  • finally:存在不能正常執(zhí)行的finally子句;

  • all:以上所有情況產(chǎn)生的警告均忽略。

這個注解的使用示例如下:

1
2
@SuppressWarning(value={"deprecation", "unchecked"})
public void myMethos() {...}

通過使用以上注解,我們告訴編譯器忽略myMethod方法中由于使用了廢棄的類或方法或是做了未檢查的轉(zhuǎn)換而產(chǎn)生的警告。

四、自定義注解

我們可以創(chuàng)建我們自己的注解類型并使用它。請看下面的示例:

1
2
3
4
5
6
7
8
9
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
    String author() default "absfree";
    String date();
    int version() default 1;
}

在自定義注解時,有以下幾點需要我們了解:

  • 注解類型是通過”@interface“關(guān)鍵字定義的;

  • 在”注解體“中,所有的方法均沒有方法體且只允許public和abstract這兩種修飾符號(不加修飾符缺省為public),注解方法不允許有throws子句;

  • 注解方法的返回值只能為以下幾種:原始數(shù)據(jù)類型), String, Class, 枚舉類型, 注解和它們的一維數(shù)組,可以為方法指定默認(rèn)返回值。

我們再把上面提到過的@SuppressWarnings這個注解類型的定義拿出來看一下,這個注解類型是系統(tǒng)為我們定義好的,它的定義如下:

1
2
3
4
5
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

我們可以看到,它只定義了一個注解方法value(),它的返回值類型為String[],沒有指定默認(rèn)返回值。我們使用@SuppressWarnings這個注解所用的語法如下:

1
@SuppressWarnings(value={"value1", "value2", ...})

也就是在注解類型名稱后的括號內(nèi)為每個注解方法指定返回值就可以使用這個注解。下面我們來看看怎么使用我們自定義的注解類型@MethodInfo:

1
2
3
4
5
6
public class AnnotationTest {
    @MethodInfo(author="absfree", date="20160410")
    public static void main(String[] args) {
        System.out.println("Using custom annotation...");
    }
}

那么現(xiàn)在問題來了,我們使用的自定義注解對于編譯器或是虛擬機來說是有意義的嗎(編譯器或是虛擬機能讀懂嗎)?顯然我們什么都不做的話,編譯器或者虛擬機是讀不懂我們的自定義注解的。下面我們來介紹以下注解的解析,讓編譯器或虛擬機能夠讀懂我們的自定義注解。 

五、注解的解析

1. 編譯時解析

編譯時注解指的是@Retention的值為CLASS的注解,對于這類注解的解析,我們只需做以下兩件事:

  • 自定義類繼承 AbstractProcessor類;

  • 重寫其中的 process 函數(shù)。

實際上,編譯器在編譯時會自動查找所有繼承自 AbstractProcessor 的類,然后調(diào)用他們的 process 方法。因此我們只要做好上面兩件事,編譯器就會主動去解析我們的編譯時注解?,F(xiàn)在,我們把上面定義的MethodInfo的Retention改為CLASS,我們就可以按照以下代碼來解析它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SupportedAnnotationTypes({ "com.custom.customannotation.MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        HashMap<String, String> map = new HashMap<String, String>();
        for (TypeElement typeElement : annotations) {
            for (Element element : env.getElementsAnnotatedWith(typeElement)) {
                MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
                map.put(element.getEnclosingElement().toString(), methodInfo.author());
            }
        }
        return false;
    }
}

@SupportedAnnotationTypes注解描述了Processor要解析的注解的名字。process 函數(shù)的annotations參數(shù)表示 表示待處理的注解集,env表示當(dāng)前或是之前的運行環(huán)境。process函數(shù)的返回值表示annotations中的注解是否被這個Processor接受。

2. 運行時注解解析

首先我們把MethodInfo注解類型中Retention的值改回原來的RUNTIME,接下來我們介紹如何通過反射機制在運行時解析我們的自定義注解類型。

java.lang.reflect包中有一個AnnotatedElement接口,這個接口定義了用于獲取注解信息的幾個方法:

1
2
3
4
T getAnnotation(Class annotationClass) //返回該程序元素的指定類型的注解,若不存在這個類型的注解則返回null
Annotation[] getAnnotations() //返回修飾該程序元素的所有注解
Annotation[] getDeclaredAnnotations() //返回直接修飾該元素的所有注解
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) //當(dāng)該程序元素被指定類型注解修飾時,返回true,否則返回false

解析我們上面的自定義注解MethodInfo的相關(guān)示例代碼如下(AnnotationParser.java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AnnotationParser {
    public static void main(String[] args) {
        try {
            Class cls = AnnotationTest.class;
            for (Method method : cls.getMethods()) {
                MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
                if (methodInfo != null) {
                    System.out.println("method name:" + method.getName());
                    System.out.println("method author:" + methodInfo.author());
                    System.out.println("method date:" + methodInfo.date());
                    System.out.println("method version:" + methodInfo.version());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

運行以上代碼我們可以得到以下輸出:

Java的注解有哪些
這說明我們已經(jīng)成功解析了自定義注解。關(guān)于注解有點我們需要明確的是,作為描述代碼本身的一種元數(shù)據(jù),注解是一種”被動“的信息。也就是說,必須由編譯器或虛擬機來“主動”解析它,它才能發(fā)揮自己的作用。

到此,相信大家對“Java的注解有哪些”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

新聞名稱:Java的注解有哪些
URL網(wǎng)址:http://muchs.cn/article26/iiohjg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、網(wǎng)站內(nèi)鏈、網(wǎng)站制作、域名注冊、外貿(mào)網(wǎng)站建設(shè)、手機網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作