偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java核心技術(shù)點(diǎn)之注解

開(kāi)發(fā) 后端
我們大家都知道Java代碼中使用注釋是為了向以后閱讀這份代碼的人解釋說(shuō)明一些事情,注解是注釋的升級(jí)版,它可以向編譯器、虛擬機(jī)等解釋說(shuō)明一些事情。本博文是對(duì)Java中注解相關(guān)知識(shí)點(diǎn)的簡(jiǎn)單總結(jié).

本博文是對(duì)Java中注解相關(guān)知識(shí)點(diǎn)的簡(jiǎn)單總結(jié),若有敘述不清晰或是不準(zhǔn)確的地方,希望大家可以指正,謝謝大家:)

一、什么是注解

[[184891]]

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

也就是說(shuō),注解是描述Java代碼的代碼,它能夠被編譯器解析,注解處理工具在運(yùn)行時(shí)也能夠解析注解。我們?cè)贘ava源文件中使用注釋?zhuān)菫榱艘院笪覀兓蛩嗽賮?lái)讀這段代碼時(shí),能夠更好地理解它。Javadoc工具可以解析我們?cè)谠创a中為類(lèi)、方法、變量等添加的描述信息,并根據(jù)這些描述信息自動(dòng)生成一個(gè)HTML文檔,這些自動(dòng)生成的文檔即可作為API幫助文檔。只要我們?yōu)轭?lèi)、方法等添加的描述信息符合Javadoc要求的語(yǔ)法,我們就能夠使用Javadoc工具根據(jù)我們的描述信息自動(dòng)生成一個(gè)幫助文檔。而注解比java注釋和Javadoc要強(qiáng)大得多,它們?nèi)咧g的重大的區(qū)別在于,Java注釋和Javadoc描述所發(fā)揮的作用僅僅到編譯時(shí)就止步了,而注解直到運(yùn)行時(shí)都能夠發(fā)揮作用。

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

二、元注解

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

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

下面我們來(lái)具體介紹一下幾種元注解。

1. Documented

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

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

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

2. Inherited

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

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

我們可以看到這個(gè)元注解類(lèi)型被@Documented所注解,能夠保留到運(yùn)行時(shí),只能用來(lái)描述注解類(lèi)型。

3. Retention

我們?cè)谏厦嬉呀?jīng)見(jiàn)到個(gè)這個(gè)元注解,它表示一個(gè)注解類(lèi)型會(huì)被保留到什么時(shí)候,比如以下代碼表示Developer注解會(huì)被保留到運(yùn)行時(shí):

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();
}

我們?cè)谑褂聾Retention時(shí),后面括號(hào)里的內(nèi)容即表示他的取值,從以上定義我們可以看到,取值的類(lèi)型為RetentionPolicy,這是一個(gè)枚舉類(lèi)型,它可以取以下值:

  • SOURCE:表示在編譯時(shí)這個(gè)注解會(huì)被移除,不會(huì)包含在編譯后產(chǎn)生的class文件中;
  • CLASS:表示這個(gè)注解會(huì)被包含在class文件中,但在運(yùn)行時(shí)會(huì)被移除;
  • RUNTIME:表示這個(gè)注解會(huì)被保留到運(yùn)行時(shí),在運(yùn)行時(shí)可以JVM訪(fǎng)問(wèn)到,我們可以在運(yùn)行時(shí)通過(guò)反射解析這個(gè)注解。

4. Target

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

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

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

  •  TYPE:表示可以用來(lái)注解類(lèi)、接口、注解類(lèi)型或枚舉類(lèi)型;
  • PACKAGE:可以用來(lái)注解包;
  • PARAMETER:可以用來(lái)注解參數(shù);
  • ANNOTATION_TYPE:可以用來(lái)注解 注解類(lèi)型;
  • METHOD:可以用來(lái)注解方法;
  • FIELD:可以用來(lái)注解屬性(包括枚舉常量);
  • CONSTRUCTOR:可以用來(lái)注解構(gòu)造器;
  • LOCAL_VARIABLE:可用來(lái)注解局部變量。

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

Java本身內(nèi)建了一些注解,下面我們來(lái)介紹一下我們?cè)谌粘i_(kāi)發(fā)中比較常見(jiàn)的注解:@Override、@Deprecated、@SuppressWarnings。相信我們大家或多或少都使用過(guò)這三個(gè)注解,下面我們一起再重新認(rèn)識(shí)一下它們。

1. @Override注解

我們先來(lái)看一下這個(gè)注解類(lèi)型的定義:

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

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

2. @Deprecated

這個(gè)注解的定義如下:

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

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

3. @SuppressWarnings

這個(gè)注解我們也比較常用到,先來(lái)看下它的定義:

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

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

  • deprecation:忽略使用了廢棄的類(lèi)或方法時(shí)的警告;
  • unchecked:執(zhí)行了未檢查的轉(zhuǎn)換;
  • fallthrough:swich語(yǔ)句款中case忘加break從而直接“落入”下一個(gè)case;
  • path:類(lèi)路徑或原文件路徑等不存在;
  • serial:可序列化的類(lèi)缺少serialVersionUID;
  • finally:存在不能正常執(zhí)行的finally子句;
  • all:以上所有情況產(chǎn)生的警告均忽略。

這個(gè)注解的使用示例如下:

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

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

四、自定義注解

我們可以創(chuàng)建我們自己的注解類(lèi)型并使用它。請(qǐ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;
}

在自定義注解時(shí),有以下幾點(diǎn)需要我們了解:

  • 注解類(lèi)型是通過(guò)”@interface“關(guān)鍵字定義的;
  • 在”注解體“中,所有的方法均沒(méi)有方法體且只允許public和abstract這兩種修飾符號(hào)(不加修飾符缺省為public),注解方法不允許有throws子句;
  • 注解方法的返回值只能為以下幾種:原始數(shù)據(jù)類(lèi)型), String, Class, 枚舉類(lèi)型, 注解和它們的一維數(shù)組,可以為方法指定默認(rèn)返回值。

我們?cè)侔焉厦嫣岬竭^(guò)的@SuppressWarnings這個(gè)注解類(lèi)型的定義拿出來(lái)看一下,這個(gè)注解類(lèi)型是系統(tǒng)為我們定義好的,它的定義如下:

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

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

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

也就是在注解類(lèi)型名稱(chēng)后的括號(hào)內(nèi)為每個(gè)注解方法指定返回值就可以使用這個(gè)注解。下面我們來(lái)看看怎么使用我們自定義的注解類(lè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)在問(wèn)題來(lái)了,我們使用的自定義注解對(duì)于編譯器或是虛擬機(jī)來(lái)說(shuō)是有意義的嗎(編譯器或是虛擬機(jī)能讀懂嗎)?顯然我們什么都不做的話(huà),編譯器或者虛擬機(jī)是讀不懂我們的自定義注解的。下面我們來(lái)介紹以下注解的解析,讓編譯器或虛擬機(jī)能夠讀懂我們的自定義注解。 

五、注解的解析

1. 編譯時(shí)解析

編譯時(shí)注解指的是@Retention的值為CLASS的注解,對(duì)于這類(lèi)注解的解析,我們只需做以下兩件事:

  • 自定義類(lèi)繼承 AbstractProcessor類(lèi);
  • 重寫(xiě)其中的 process 函數(shù)。

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

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)前或是之前的運(yùn)行環(huán)境。process函數(shù)的返回值表示annotations中的注解是否被這個(gè)Processor接受。

2. 運(yùn)行時(shí)注解解析

首先我們把MethodInfo注解類(lèi)型中Retention的值改回原來(lái)的RUNTIME,接下來(lái)我們介紹如何通過(guò)反射機(jī)制在運(yùn)行時(shí)解析我們的自定義注解類(lèi)型。

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

1
2
3
4
T getAnnotation(Class annotationClass) //返回該程序元素的指定類(lèi)型的注解,若不存在這個(gè)類(lèi)型的注解則返回null
Annotation[] getAnnotations() //返回修飾該程序元素的所有注解
Annotation[] getDeclaredAnnotations() //返回直接修飾該元素的所有注解
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) //當(dāng)該程序元素被指定類(lèi)型注解修飾時(shí),返回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();
        }
    }
}

運(yùn)行以上代碼我們可以得到以下輸出:


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

六、參考資料

1. Java Documention

2. 公共技術(shù)點(diǎn)之Java注解

3. Java 注解

責(zé)任編輯:張燕妮 來(lái)源: absfree
相關(guān)推薦

2022-10-11 08:37:43

Servlet配置版本

2009-06-15 17:54:50

Java核心技術(shù)

2011-11-23 15:53:54

Java核心技術(shù)框架

2022-05-07 14:31:46

物聯(lián)網(wǎng)

2017-04-06 12:43:48

2016-11-15 14:33:05

Flink大數(shù)據(jù)

2009-06-26 16:01:39

EJB組織開(kāi)發(fā)EJB容器EJB

2023-06-14 08:49:22

PodKubernetes

2025-09-15 06:25:00

2022-05-09 08:21:29

Spring微服務(wù)Sentinel

2009-06-19 16:38:45

JDBC簡(jiǎn)介J2EE

2017-03-24 17:17:35

限流節(jié)流系統(tǒng)

2010-06-29 09:06:39

Java思想Java虛擬機(jī)

2011-05-18 09:32:14

java

2020-12-10 11:00:37

JavaJVM命令

2019-05-15 08:26:44

工業(yè)物聯(lián)網(wǎng)MQTT物聯(lián)網(wǎng)

2016-12-12 09:01:47

Amazon Go核心技術(shù)

2016-11-22 17:05:54

Apache Flin大數(shù)據(jù)Flink

2019-03-05 14:57:21

大數(shù)據(jù)Hadoop框架

2019-05-15 08:40:34

工業(yè)物聯(lián)網(wǎng)MQTT物聯(lián)網(wǎng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)