必知必會之Java註解
必知必會之Java註解
目錄
不定期更新中……
- ElementType
- RetentionPolicy
- [@SuppressWarnings 關鍵字](#@SuppressWarnings 關鍵字)
元註解
@Documented
僅用在註解類上,表示在使用 javadoc 工具生成幫助文檔時,使用該註解的類會在 API 文檔中展示該註解。
註解版本:1.5+
場景舉例:
-
創建一個註解類 TestAnnotation
package com.xs.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Documented @Target(ElementType.TYPE) public @interface TestAnnotation { public String value() default "javadoc"; }
-
創建一個使用該註解的類 DocumentTest
package com.xs.annotation; @TestAnnotation public class DocumentedTest { }
-
生成 javadoc(使用 javadoc 命令 或 使用 eclipse、IDEA 等 IDE 提供的 javadoc 生成工具)
-
打開生成的 API 文檔(/doc/index.html),如下:
-
若刪除註解類 TestAnnotation 中的 @Documented 註解,再次生成 javadoc,註解消失。
@Inherited
僅用在註解類上,被它修飾的註解具有繼承性。也就是說,在一個類上使用被 @Inherited 標註的註解,其子類也會繼承這些被 @Inherited 標註的註解。
註解版本:1.5+
場景舉例:
-
創建一個帶有 @Inherited 的註解類 InheritedAnnotation
package com.xs.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Target; @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface InheritedAnnotation { public String value() default "Inherited"; }
-
創建一個使用該註解的類 InheritedParent
package com.xs.annotation; import com.xs.annotation.TestInheritedAnnotation; @InheritedAnnotation(value="parent") public class InheritedParent { }
-
為 InheritedParent 類創建子類 InheritedChild
package com.xs.annotation; import com.xs.annotation.InheritedParent; public class InheritedChild extends InheritedParent { public static void main(String[] args) { Class<InheritedChild> child = InheritedChild.class; InheritedAnnotation annotation = child.getAnnotation(InheritedAnnotation.class); System.out.println(annotation.value()); } }
-
運行 main 方法,輸出如下。
parent
@Retention
僅用在註解類上,用來描述註解保留的時間範圍。一共有三種策略,定義在 RetentionPolicy 枚舉中,分別是:源文件保留、編譯期保留、運行期保留,默認值為編譯期保留。運行期保留可以用來獲取註解資訊。
註解版本:1.5+
場景舉例:
-
分別實現三種策略
package com.xs.annotation.meta; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.SOURCE) public @interface SourcePolicy { } @Retention(RetentionPolicy.CLASS) public @interface ClassPolicy { } @Retention(RetentionPolicy.RUNTIME) public @interface RuntimePolicy { }
-
創建一個類,並使用以上三種註解去註解三個方法
package com.xs.annotation.meta; public class RetentionTest { @SourcePolicy public void sourcePolicy() { } @ClassPolicy public void classPolicy() { } @RuntimePolicy public void runtimePolicy() { } }
-
生成位元組碼文件
javap -verbose RetentionClass ### 以下為輸出結果 ### 警告: 二進位文件RetentionClass包含com.xs.annotation.meta.RetentionClass Classfile /Users/lihuiming/git/xs/xs-technology/xs-learning-annotation/target/classes/com/xs/annotation/meta/RetentionClass.class Last modified 2021-2-20; size 709 bytes MD5 checksum 88516f888e7e83d00ffe708e32d852a0 Compiled from "RetentionClass.java" public class com.xs.annotation.meta.RetentionClass minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#20 // java/lang/Object."<init>":()V #2 = Class #21 // com/xs/annotation/meta/RetentionClass #3 = Class #22 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 Lcom/xs/annotation/meta/RetentionClass; #11 = Utf8 sourcePolicy #12 = Utf8 classPolicy #13 = Utf8 RuntimeInvisibleAnnotations #14 = Utf8 Lcom/xs/annotation/meta/RetentionClassPolicy; #15 = Utf8 runtimePolicy #16 = Utf8 RuntimeVisibleAnnotations #17 = Utf8 Lcom/xs/annotation/meta/RetentionRuntimePolicy; #18 = Utf8 SourceFile #19 = Utf8 RetentionClass.java #20 = NameAndType #4:#5 // "<init>":()V #21 = Utf8 com/xs/annotation/meta/RetentionClass #22 = Utf8 java/lang/Object { public com.xs.annotation.meta.RetentionClass(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/xs/annotation/meta/RetentionClass; public void sourcePolicy(); descriptor: ()V flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 12: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this Lcom/xs/annotation/meta/RetentionClass; public void classPolicy(); descriptor: ()V flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 16: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this Lcom/xs/annotation/meta/RetentionClass; RuntimeInvisibleAnnotations: 0: #14() public void runtimePolicy(); descriptor: ()V flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 20: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this Lcom/xs/annotation/meta/RetentionClass; RuntimeVisibleAnnotations: 0: #17() } SourceFile: "RetentionClass.java"
-
從位元組碼可以看出,編譯器沒有記錄下 sourcePolicy() 方法的註解資訊,分別使用了 RuntimeInvisibleAnnotations 和 RuntimeVisibleAnnotations 屬性去記錄了classPolicy()方法 和 runtimePolicy()方法 的註解資訊。
@Target
僅用在註解類上,用來標註註解的元素類型(ElementType),即設置註解的適用範圍。如果沒有標註 @Target,那麼該註解可以作用在任何地方。
註解版本:1.5+
場景舉例:
package javax.validation;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface Valid {
}
常用註解
@Deprecated
標註在類、介面、成員方法和成員變數上,表示某個元素(類、方法等)已過時。當其他程式使用已過時的元素時,編譯器將會給出警告。
註解版本:1.5+
場景舉例:
@Deprecated
public class DeprecatedClass {
@Deprecated
public int value;
@Deprecated
public void m1() {
System.out.println("Deprecated");
}
}
@FunctionalInterface
Java 8 版本後,Java引入函數式編程。@FunctionalInterface 就是 Java 8 版本新增的註解,用來標註函數式介面。
什麼是函數式介面?如果介面中只有一個抽象方法(可以包含多個默認方法或多個 static 方法),那麼該介面就是函數式介面。函數式介面是為 Java 8 的 Lambda 表達式準備的。
@FunctionalInterface 本身只起到標註作用,用來告訴編譯器檢查這個介面是否符合函數式介面的規範(只能包含一個抽象方法)。
註解版本:1.8+
場景舉例:
package org.springframework.boot;
@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
@Override
標註在方法上,用來標註方法為重寫方法。
註解版本:1.5+
場景舉例:
public class Parent {
public void m1() {
System.out.println("Parent");
}
}
public class Child extends Parent {
@Override
public void m1() {
System.out.println("Child");
}
}
@PostConstruct
@PostConstruct 該註解被用來修飾一個非靜態的 void() 方法。被 @PostConstruct 修飾的方法會在伺服器載入 Servlet 的時候運行,並且只會被伺服器執行一次。PostConstruct 在構造函數之後執行,init() 方法之前執行。
該註解的方法在 Spring 整個 Bean 初始化中的執行順序:Constructor(構造方法) -> @Autowired(依賴注入) -> @PostConstruct(注釋的方法)。
註解版本:1.0+
場景舉例:
public class Test {
private static Test test = new Test();
@Autowired
private OtherService otherService;
@PostConstruct
public void init() {
System.out.println("init");
test.otherService = otherService;
}
}
@SafeVarargs
標註在 static 或 final 方法上,表示被該註解修飾的方法取消顯示指定的編譯器警告。
註解版本:1.7+
場景舉例:
public class SafeVarargsClass {
public static void main(String[] args) {
// 沒有 @SafeVarargs 會有編譯警告
display("10", 20, 30);
}
@SafeVarargs
public static <T> void m1(T... array) {
for (T arg : array) {
System.out.println(arg.getClass().getName() + ":" + arg);
}
}
}
@SuppressWarnings
標註在類或方法上,表示被該註解修飾的程式元素(以及該程式元素中的所有子元素)取消顯示指定的編譯器警告,且會一直作用於該程式元素的所有子元素。
註解的使用有以下三種:
-
抑制單類型的警告:@SuppressWarnings(“unchecked”)
-
抑制多類型的警告:@SuppressWarnings(“unchecked”,”rawtypes”)
-
抑制所有類型的警告:@SuppressWarnings(“unchecked”)
全部關鍵字請參考附錄:[@SuppressWarnings 關鍵字](#@SuppressWarnings 關鍵字)
註解版本:1.5+
場景舉例:
@SuppressWarnings("unchecked","rawtypes")
public class SuppressWarningsClass {
@SuppressWarnings("unchecked")
public void m1() {
System.out.println("unchecked");
}
}
附錄
ElementType
The constants of this enumerated type provide a simple classification of the syntactic locations where annotations may appear in a Java program. These constants are used in {@link Target java.lang.annotation.Target} meta-annotations to specify where it is legal to write annotations of a given type.
版本:1.5+
取值 | 釋義 |
---|---|
TYPE | 用於描述類、介面(包括註解類型)、枚舉 |
FIELD | 用於描述欄位(包括枚舉、常量) |
METHOD | 用於描述方法 |
PARAMETER | 用於描述形參 |
CONSTRUCTOR | 用於描述構造器 |
LOCAL_VARIABLE | 用於描述局部變數 |
ANNOTATION_TYPE | 用於描述註解類型 |
PACKAGE | 用於描述包 |
TYPE_PARAMETER | JAVA 8 新增,作用在泛型上 |
TYPE_USE | JAVA 8 新增,用於描述任何類型 |
RetentionPolicy
Annotation retention policy. The constants of this enumerated type describe the various policies for retaining annotations. They are used in conjunction with the {@link Retention} meta-annotation type to specify how long annotations are to be retained.
版本:1.5+
取值 | 釋義 |
---|---|
SOURCE | 註解只保留在源文件,當Java文件編譯成class文件的時候,註解被遺棄; |
CLASS | 註解被保留到 class文件,但jvm載入class文件時候被遺棄,默認為該級別; |
RUNTIME | 註解不僅被保存到 class文件中,jvm載入class文件之後,仍然存在; |
@SuppressWarnings 關鍵字
關鍵字 | 用途 |
---|---|
all | 抑制所有警告 |
boxing | 抑制裝箱、拆箱操作時候的警告 |
cast | 抑制映射相關的警告 |
dep-ann | 抑制啟用注釋的警告 |
deprecation | 抑制過期方法警告 |
fallthrough | 抑制在 switch 中缺失 breaks 的警告 |
finally | 抑制 finally 模組沒有返回的警告 |
hiding | 抑制相對於隱藏變數的局部變數的警告 |
incomplete-switch | 忽略不完整的 switch 語句 |
nls | 忽略非 nls 格式的字元 |
null | 忽略對 null 的操作 |
rawtypes | 使用 generics 時忽略沒有指定相應的類型 |
restriction | 抑制禁止使用勸阻或禁止引用的警告 |
serial | 忽略在 serializable 類中沒有聲明 serialVersionUID 變數 |
static-access | 抑制不正確的靜態訪問方式警告 |
synthetic-access | 抑制子類沒有按最優方法訪問內部類的警告 |
unchecked | 抑制沒有進行類型檢查操作的警告 |
unqualified-field-access | 抑制沒有許可權訪問的域的警告 |
unused | 抑制沒被使用過的程式碼的警告 |
——————————————————————————————————————————————
原創:西狩
編寫日期 / 修訂日期:2021-02-24 / 2021-02-24
版權聲明:本文為部落客原創文章,遵循 CC BY-NC-SA-4.0 版權協議,轉載請附上原文出處鏈接和本聲明。