Java ”框架 = 註解 + 反射 + 設計模式“ 之 註解詳解

Sea發表於2023-02-22

Java ”框架 = 註解 + 反射 + 設計模式“ 之 註解詳解

在這裡插入圖片描述

每博一文案

剎那間我真想令時光停住,好讓我回顧自己,回顧失去的年華,緬懷哪個穿一身短小的連衣裙
和瘦窄的短衫的小女孩。讓我追悔少年時代,我心靈的愚鈍無知,它輕易地錯過了我一生中本來
可以獲得歡樂和幸福。
                             —————— 《平凡的世界》
                             
真的,如果痛苦不能改變生存,那還不如平靜地將自己毀滅,毀滅,一切都毀滅了,
只有生命還在苟延殘喘,這樣的生命還有有什麼存在的價值。
                            —————— 《平凡的世界》
                     

@

1. 註解的概念

註解,一種後設資料形式提供了一個不屬於程式本身的程式的資料。註解對他們註解的程式碼的操作沒有直接的影響。

註解有很多用途,其中:

  • 編譯器的資訊 - 編譯器可以使用註解來檢測錯誤或抑制警告。
  • 編譯和部署時處理 - 軟體工具可以處理註解資訊以生成程式碼,XML 檔案等。
  • 執行時處理 - 一些註解可以在執行時檢查

JDK5.0 開始,Java增加了對後設資料(MetaData) 的支援,也就是 Annotation 註解。

  • 註解: 其實就是程式碼裡的 特殊標記 ,這些標記可以在編譯,類載入,執行時被讀取,並執行相應的處理。透過使用 註解,

程式設計師可以在不改變原有的邏輯的情況下,在原始檔種嵌入一些補充的資訊。程式碼分析工具,開發工具和部署工具可以透過這些補充資訊進行驗證或進行部署。

  • 註解: 可以像修飾符一樣被使用,可以用於 修飾:包,類,構造器,方法,成員變數,引數,區域性變數的宣告 。這些資訊被儲存在 註解 Annotaion 的“ name = value” 鍵值對中。

  • JavaSE中,註解的使用目的比較簡單,例如標記過時的功能,忽略警告等。在JavaEE/Android中註解佔據了更重要的角色,例如

    用來配置應用程式的任何切面,代替JavaEE舊版中所遺留的繁冗 程式碼和XML配置等。

  • 未來的開發模式都是基於註解的,JPA 是基於註解的,Spring2.5 以上都是基於註解的,Hibernate3.x 以後也是基於註解的,

現在Struts2 有一部分也是基於註解的了。註解是一種趨勢,一定程度上可以說:框架 = 註解 + 反射 + 設計模式

2. 註解的作用

JVM 的角度看,註解本身對程式碼邏輯沒有任何影響,如何使用註解完全由工具決定。

Java的註解可以分為三類:

  • 第一類:是由編譯器使用的註解:換句話說就是給編譯器看的,不是給 JVM 看的。例如:
    • @Override : 讓編譯器檢查該方法是否正確的實現了 重寫操作。
    • @Deprecated : 表示所修飾的元素(類,方法等)已過時了,不建議使用它了。
    • @SuppressWarnings: 告訴編譯器忽略此處程式碼產生的警告。
  • 第二類: 是由工具處理 .class 檔案使用的註解,比如有些工具會在載入 class 的時候,對 class 做動態修改,實現一些特殊的功能。這類註解會被編譯進入到 .class 檔案,但載入結束後並不會存在於記憶體中。這類註解只被一些底層使用,一般我們不必自己處理。
  • 第三類: 是在程式執行期間能夠讀取的註解,它們在載入後一直存在於 JVM 中,這也是最常用的註解。例如:一個配置了@PostConstruct 的方法會在呼叫構造方法後自動被呼叫,(這是Java程式碼讀取該註解實現的功能,JVM 並不會識別該註解)。

3. 文件註釋中的註解

在這裡插入圖片描述

在這裡插入圖片描述

  • @author 標明開發該類模組的作者,多個作者之間使用,分割。
  • @version 標明該類的模組的版本。
  • @see 參考轉向,也就是相關類的主題。
  • @since 從哪個版本開始增加的。
  • @param 對方法中某引數的說明,如果沒有引數就不能寫。
  • @return 對方法返回值的說明,如果方法的返回值型別是 void 就不能寫
  • @exception 對方法可能丟擲的異常進行說明,如果方法沒有用 throws 顯丟擲的異常就不能寫 其中:
    • @param @ return 和 @ exeption 這三個標記都是隻用於方法的。
    • @param 的格式要求:@param 形參名 形參型別 形參說明
    • @return 的格式要求:@return 返回值型別 返回值說明
    • @exception 的格式要求:@exception 異常型別 異常說明
    • @ param 和 @exception 可以並列多個。

4. 自定義註解

Annotaion註解 其實也是一種引用資料型別,編譯之後也是生成 xxx.class 位元組碼檔案的。

  • 定義新的 Annotation 註解 型別使用 @interface 關鍵字

  • 自定義註解自動實現了 java.lang.annotation.Annotation介面

在這裡插入圖片描述

在這裡插入圖片描述

自定義註解的格式如下:

public @interface MyAnnotation {
    
}

// 
[修飾列表] @interface 註解名/(註解類名) {
    
}

使用 IDEA 建立一個 註解型別: 滑鼠右鍵 ——> new 一個選擇 :

在這裡插入圖片描述

如下檢視該 我們該自定義的註解 MyAnnotation 的 UML 圖:可以清楚的看到該 註解型別是自動繼承了該 java.lang.annotation.Annotation 介面的

在這裡插入圖片描述

但是事實上卻是自動實現了 java.lang.annotation.Annotation 介面。

在這裡插入圖片描述

Java 8之前,註解只能是在宣告的地方所使用,Java8 開始,註解可以應用 在任何地方 。這裡的任何地方包括:包,類,構造器,方法,成員變數,引數,區域性變數的宣告 。這些資訊被儲存在 註解 Annotaion 的“ name = value” 鍵值對中。

舉例如下: 並沒有出現任何的報錯的情況。

在這裡插入圖片描述

4.1 註解中的屬性

在註解中可以定義屬性。

Java中的註解中的屬性:看著像方法,但實際在註解當中是屬性 name

格式如下:

String value();
// 資料型別 屬性名();  // 看似是方法,其實在註解中是屬性

註解中的屬性可以是任何型別:byte, short, int, long, float, double, boolean, char, String, long, Class, 列舉型別。再或者是自定義型別。

舉例:

public @interface MyAnnotation {
    
    String value();

}

注意: 如果該註解中定義了屬性,則宣告使用該註解時 必須 為其註解中的屬性值賦上值,不然,是會報錯的。

如下,我們為該 @MyAnnotation 註解定義了屬性,使用時卻沒有賦值,報如下編譯錯誤。

在這裡插入圖片描述

為註解中的屬性賦值的格式如下:

@MyAnnotaion(value="Tom") // 注意:在該註解中定義的是什麼型別的值,就賦值對應的值,不然會報錯的
// @註解名(註解中的屬性名=對應賦值的屬性值)

舉例:

在這裡插入圖片描述

如果該註解中只有一個屬性值,並且該註解的屬性名為 value ,則在賦值時,可以省略其 為value的屬性名,直接寫值

注意一定要滿足兩個條件:1. 該註解中只有一個屬性值,2.該屬性名為 value

舉例:

在這裡插入圖片描述


為註解中的多個屬性賦值格式如下: 多個屬性值,使用逗號分隔開來,就可以了。

 @MyAnnotation(value = "Tom",value2 = "123")
// @註解名(註解中的屬性名=值,註解中的屬性名=值) :多個屬性值使用逗號分隔開。

注意: 當註解中存在多個屬性值時,其中所有該註解中的屬性值都必須賦值,不然編譯報錯,如下:

在這裡插入圖片描述

必須將註解中的所有屬性值都賦值上值才行:如下:如果註解中存在兩個或兩個以上的屬性,就算其中存在一個屬性名為 value ,其賦值時,該value 屬性名是不可以省略的。必須寫明所有的屬性名的進行賦值。[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳
在這裡插入圖片描述

註解中的屬性可以設定預設值,使用關鍵字``格式如下:

String value() default "Tom";
// 資料型別 屬性名() default  預設值;  注意需要和定義的型別保證一致。

舉例:

public @interface MyAnnotation {
    String value() default "Tom";

}

註解中屬性設定了,預設值的是可以選擇不進行賦值操作,使用定義的預設值。

舉例如下:

在這裡插入圖片描述

4.2 註解中屬性為:陣列的賦值

註解中的屬性值是可以定義為陣列屬性的格式如下:

String[] arr(); // 定義陣列為屬性值
資料型別[] 屬性名(); 

舉例:

public @interface MyAnnotation {

    String value();

    String[] arr();

}

註解中以陣列為屬性的賦值格式如下:

@MyAnnotation(value = "Tom",arr = {"hello","world"})
@註解名(屬性名=值,屬性名={值,值})

舉例:

在這裡插入圖片描述

當陣列屬性所賦值的引數只有一個時,可以省略{} 花括號。如下

在這裡插入圖片描述

5. JDK 內建的三個基本註解

下面我們來認識一下,JDK 中三個常見的基本註解。

5.1 @Override: 限定重寫父類方法, 該註解只能用於方法

在這裡插入圖片描述

@Override : 的作用就是在編譯期間:讓編譯器檢查該方法是否正確的實現了 重寫 操作。其中的重寫的方法名是否存在錯誤,方法的返回值型別是否是父類中/介面中的一致。不一致編譯報錯,提示我們改正。

@OVerride 註解的原始碼,可以看到該註解是沒有定義屬性的。

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

注意 : 該註解只能使用在方法上(因為該註解的原始碼中被@Target(ElementType.METHOD)元註解修飾了),在其他位置上是會編譯報錯的。如下:

在這裡插入圖片描述


@OVerride 註解的使用: 較少了我們程式設計程式時,上的簡單符號上以及一些基本的語法錯誤。

在這裡插入圖片描述

5.2 @Deprecated: 用於表示所修飾的元素(類, 方法等)已過時。

在這裡插入圖片描述

@Deprecated : 該註解表示:表示所修飾的元素(類,方法等)已過時了,不建議使用它了。建議替換成其他的方法。

@Depecated 原始碼: 可以看到該註解是沒有定義屬性的。

package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
 * A program element annotated &#64;Deprecated is one that programmers
 * are discouraged from using, typically because it is dangerous,
 * or because a better alternative exists.  Compilers warn when a
 * deprecated program element is used or overridden in non-deprecated code.
 *
 * @author  Neal Gafter
 * @since 1.5
 * @jls 9.6.3.6 @Deprecated
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

常見的,在我們的 java.util.lang 包下的 Date 中的 Date(String s) 構造器是被 @Deprecated 註解修飾了的。

在這裡插入圖片描述

在IDEA 中 如果我們呼叫了,被 @Deprecated 修飾的屬性,方法,構造器,會給一個直觀的將該屬性/方法以刪除線的方式顯示處理並提示你建議使用別的方式替換 。如下

在這裡插入圖片描述

我們也可以自己寫一個這樣的被@Deprecated 修飾的屬性/方法/類/構造器。舉例如下:

在這裡插入圖片描述

5.3 @SuppressWarnings: 抑制編譯器警告

在這裡插入圖片描述

@SuppressWarnings ** :指示應該在註解元素(以及包含在該註解元素中所有程式元素中的所有程式元素)中取消顯示指定的編譯器警告。換句話說:就是告訴編譯器忽略此處程式碼產生的警告**。 注意是警告不是異常。

@SuppressWarnings的原始碼 ,可以看到該註解定義了一個名為 value 的屬性。


package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
 * Indicates that the named compiler warnings should be suppressed in the
 * annotated element (and in all program elements contained in the annotated
 * element).  Note that the set of warnings suppressed in a given element is
 * a superset of the warnings suppressed in all containing elements.  For
 * example, if you annotate a class to suppress one warning and annotate a
 * method to suppress another, both warnings will be suppressed in the method.
 *
 * <p>As a matter of style, programmers should always use this annotation
 * on the most deeply nested element where it is effective.  If you want to
 * suppress a warning in a particular method, you should annotate that
 * method rather than its class.
 *
 * @author Josh Bloch
 * @since 1.5
 * @jls 4.8 Raw Types
 * @jls 4.12.2 Variables of Reference Type
 * @jls 5.1.9 Unchecked Conversion
 * @jls 5.5.2 Checked Casts and Unchecked Casts
 * @jls 9.6.3.5 @SuppressWarnings
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}

舉例: 這裡我們定義一個 int num = 1 / 0 語句,IDEA 該我們提示了警告了。

在這裡插入圖片描述

當我們加上了 @SuppressWarnings IDEA 就沒有這個警告了。如下:

在這裡插入圖片描述

在這裡插入圖片描述

具體的其他應用大家可以移步至:???
https://blog.csdn.net/qq_43842093/article/details/122386115?ops_request_misc=&request_id=&biz_id=102&utm_term=%20@SuppressWarnings%E7%9A%84%E4%BD%BF%E7%94%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-3-122386115.142
Eclipse Galileo版本支援的抑制警告的名稱:

關鍵字 用途
all to suppress all warnings (抑制所有警告)
boxing to suppress warnings relative to boxing/unboxing operations (抑制裝箱、拆箱操作時候的警告)
cast to suppress warnings relative to cast operations (抑制對映相關的警告)
dep-ann to suppress warnings relative to deprecated annotation (抑制啟用註釋的警告)
deprecation to suppress warnings relative to deprecation (抑制過期方法警告)
fallthrough to suppress warnings relative to missing breaks in switch statements (抑制確在switch中缺失breaks的警告)
finally to suppress warnings relative to finally block that don’t return (抑制finally模組沒有返回的警告)
hiding to suppress warnings relative to locals that hide variable(抑制相對於隱藏變數的區域性變數的警告)
incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)(忽略沒有完整的switch語句)
nls to suppress warnings relative to non-nls string literals( 忽略非nls格式的字元)
null to suppress warnings relative to null analysis( 忽略對null的操作)
rawtypes to suppress warnings relative to un-specific types when using generics on class params( 使用generics時忽略沒有指定相應的型別)
restriction to suppress warnings relative to usage of discouraged or forbidden references( 抑制禁止使用勸阻或禁止引用的警告)
serial to suppress warnings relative to missing serialVersionUID field for a serializable class( 忽略在serializable類中沒有宣告serialVersionUID變數)
static-access to suppress warnings relative to incorrect static access( 抑制不正確的靜態訪問方式警告)
synthetic-access to suppress warnings relative to unoptimized access from inner classes( 抑制子類沒有按最優方法訪問內部類的警告)
unchecked to suppress warnings relative to unchecked operations( 抑制沒有進行型別檢查操作的警告)
unqualified-field-access to suppress warnings relative to field access unqualified( 抑制沒有許可權訪問的域的警告)
unused to suppress warnings relative to unused code( 抑制沒被使用過的程式碼的警告)

6. 元註解

有一些註解可以修飾其他註解,這些註解就稱為元註解(meta annotation)。Java標準庫已經定義了一些元註解,我們只需要使用元註解,通常不需要自己去編寫元註解。

6.1 @Target

在這裡插入圖片描述

@Target 原始碼:其中存在一個型別為 ElementType[] 列舉型別陣列屬性名為 value 的屬性。

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

ElementType的列舉原始碼 :

/package java.lang.annotation;
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Target : 最常用的元註解是@Target。使用@Target可以定義Annotation能夠被應用於原始碼的哪些位置:

  • 類或介面:ElementType.TYPE
  • 欄位:ElementType.FIELD
  • 方法:ElementType.METHOD
  • 構造方法:ElementType.CONSTRUCTOR
  • 方法引數:ElementType.PARAMETER

舉例:

在這裡插入圖片描述

在這裡插入圖片描述

@Target元註解中的 value 屬性是列舉陣列型別的,可以賦值多個值:比如表示該註解可以宣告在方法,變數,類中 ,舉例:

在這裡插入圖片描述

6.2 @Retention

在這裡插入圖片描述

@Retention 原始碼 : 我們可以看到如下註解中只定義了一個RetentionPolicy 的列舉型別名為 value 的屬性名的屬性

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

RetentionPolicy 列舉型別的原始碼

package java.lang.annotation;


public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

@Retention : 另一個重要的元註解@Retention定義了Annotation的生命週期:

@Rentention 時必須為該 value 成員變數指定值

  • 僅編譯期:RetentionPolicy.SOURCE 表示該註解的生命週期只在編譯期間有效,在原始檔中有效(即原始檔保留),編譯器直接丟棄這種策略的註釋。
  • 僅class檔案:RetentionPolicy.CLASS : 在class檔案中有效(即class保留) , 當執行 Java 程式時, JVM 不會保留註解。 這是預設值
  • 執行期:RetentionPolicy.RUNTIME,注意:只有定義該屬性的註解,才能被反射讀取到。上面兩種方式都無法被反射讀取到的。

如果@Retention不存在,則該Annotation預設為CLASS。因為通常我們自定義的Annotation都是RUNTIME,所以,務必要加上@Retention(RetentionPolicy.RUNTIME)這個元註解:

舉例:

在這裡插入圖片描述

6.3 @Documented

在這裡插入圖片描述

@Documented: 用於指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文件。預設情況下,javadoc是不包括註解的。

  • 定義為Documented的註解必須設定Retention值為RUNTIME

@Documented 的原始碼 從原始碼看,該註解沒有任何屬性。


package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

6.4 @Inherited

在這裡插入圖片描述

@Inherited: 被它修飾的 Annotation 將具有繼承性。如果某個類使用了被

@Inherited : 修飾的 Annotation, 則其子類將自動具有該註解。

  • 比如:如果把標有@Inherited註解的自定義的註解標註在類級別上,子類則可以繼承父類類級別的註解

  • 實際應用中,使用較少

@Inherited 原始碼 從原始碼看,該註解沒有任何屬性。


package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

7. 透過反射獲取到註解資訊

想要讓反射可以讀取到註解中的資訊,則該反射中的元註解必須是: @Retention(RetentionPolicy.RUNTIME) 才行。

舉例: 這裡我們使用反射讀取到 fun() 方法中的 註解中的 value 屬性值:

註解

package blogs.blog10;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)  // 生命週期在:執行期,才可以被反射讀取到
public @interface MyAnnotation {
    String value() default "Tom";

}

package blogs.blog10;


import java.lang.reflect.Method;

public class AnnotationTest {

    public static void main(String[] args) {
        Method method = null;

        try {
            // 獲取類載入器,類物件
            Class clazz = Class.forName("blogs.blog10.AnnotationTest"); // 全類路徑名

            // 獲取 fun()方法
            method = clazz.getDeclaredMethod("fun");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        // 判斷該方法是否存在該註解,存在才讀取該註解上的屬性值
        if(method.isAnnotationPresent(MyAnnotation.class)) {
            // 獲取該註解物件
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            // // 獲取該註解的屬性值,就像物件.屬性一樣
            String value = annotation.value();
            System.out.println(value);
        }

    }

    @MyAnnotation("lihua")
    public void fun() {
        int num = 0;
    }

}




在這裡插入圖片描述

8. 總結:

  1. 設計註解型別時,必須考慮該型別註解的基數。現在可以使用註解零次,一次,或者如果註解的型別被標記為 @Repeatable 多次。也可以透過使用 @Target 元註解來限制註解型別的使用位置。例如,您可以建立只能在方法和欄位上使用的可重複註解型別。重要的是仔細設計註解型別,以確保使用註解的程式設計師發現它儘可能靈活和強大。
  2. 註解的作用:減少程式中的錯誤,提高程式設計師的開發效率。以及框架上的運用。
  3. 注意:註解中的屬性必須賦值,不然編譯無法透過,除非該屬性設定了預設值資訊,建議註解中的屬性設定上預設值。
  4. 當註解中只有一個屬性,並且該屬性名為 value ,則在賦值上可以省略屬性名。
  5. 註解多個值上的賦值,以及陣列型別的屬性值的賦值。
  6. 元註解:修飾註解上的註解,特別掌握:@Target,@Retention 這兩個元註解,其中的屬性值上的賦值的意義。

9. 最後:

限於自身水平,其中存在的錯誤,希望大家給予指教,韓信點兵——多多益善 。謝謝大家,江湖再見,後會有期 !!!

在這裡插入圖片描述

相關文章