【Java.Core】註解 - Annotation
註解(Annotation)為我們在程式碼中新增資訊提供了一種形式化的方法,我們可以在稍後某個時刻方便地使用這些資料(通過解析註解來使用這些資料)。
註解是那些插入到原始碼中用於工具處理的標籤。這些標籤可以在原始碼層次上進行處理,或者可以通過編譯器將它們納入到類檔案中。
註解不會改變對編寫的程式的編譯方式。
為了能夠受益於註解,需要選擇一個處理工具,然後向你的處理工具可以理解的程式碼中插入註解,之後運用該處理工具。
註解的作用
註解常見的作用有以下幾種:
- 生成文件。這是最常見的,也是java最早提供的註解。常用的有@see @param @return等;
- 跟蹤程式碼依賴性,實現替代配置檔案功能。如Spring中的基於註解配置。作用是減少配置;
- 在編譯時進行格式檢查,如@Override放在方法前,如果這個方法並不是覆蓋了超類方法,則編譯時就能檢查出;
標準註解
JDK5.0定義了7個註解介面。其中三個是規則介面,可以用它們來註釋你的原始碼中的項。其他四個是元註釋,用於描述註解介面的行為屬性。
正規註解
@Deprecated註解可以被新增到任何不在鼓勵使用的條目上。當使用一個已過時的條目時,編譯器將會發出警告。
@SuppressWarning註釋會告知編譯器阻止特殊型別的警告資訊。
@Override註釋只能應用到方法上,編譯器會阻止具有這種註釋的方法去覆蓋一個來自於超類的方法。
元註解
@Target元註釋
@Target元註釋可以應用於一個註釋,以限制該註釋可以應用到哪些條目上。
下表顯式了所有可能的取值情況,它們屬於列舉型別ElementType。可以指定任意數量的元素型別,用括號括起來。
元素型別 | 註釋使用場合 |
ElementType ANNOTATION_TYPE |
註釋型別宣告 |
ElementType PACKAGE |
包 |
ElementType TYPE |
類(包括enum)及介面(包括註解型別) |
ElementType METHOD |
方法 |
ElementType CONSTRUCTOR |
構造器 |
ElementType FIELD |
成員域(包括enum常量) |
ElementType PARAMETER |
方法或構造器引數 |
ElementType LOCAL_VARIABLE |
本地變數 |
一條沒有@Target限制的註解可以應用與任何條目上。
編譯器只檢查是否將一條註解應用到了某個允許的條目上,否則會導致一個編譯器錯誤。
例如Spring中的註釋@Controller定義:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
String value() default "";
}
@Retention元註解
@Retention元註釋用於指定一條註釋應該保留多長時間,只能將其指定為表中的任意值,預設為RetentionPolicy.CLASS.
保留規則 | 描述 |
RetentionPolicy SOURCE |
不包括在類檔案*.class中的註釋 |
RetentionPolicy CLASS |
類檔案中的註釋,但是虛擬機器不需要將它們載入 |
RetentionPolicy RUNTIME |
類檔案中的註釋,並有虛擬機器載入,通過反射API可以獲得它們 |
@Documentd元註解
@Documentd元註釋為像Javadoc這樣的文件工具提供了一些提示。
@Inherited元註解
@Inherited元註解只能應用與對類的註解。如果一個類具有繼承註解,那麼它的所有子類都自動具有同樣的註解。
註解語法
一個註解是由一個註解介面@interface來定義的:
modifier @interface AnnotationName{
element declaration 1
element declaration 2
...
...
}
註解中的每一個方法實際上是宣告瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別,返回值型別只能是基本型別,Class,String,enum,註解型別,或由前面型別所組成的陣列。可以通過default來宣告引數的預設值。
每個元素具有下面這種形式:
type elementName();
或者
type elementName() default value;
例如:下面這個註解具有兩個元素:assingedTo和severity。
public @interface BugReport{
String assignedTo() default "[none]";
int severity();
}
每個註解使用時都具有下面這種格式:
@AnnotationName(elementName1 = value1, elementName2 = value2, ... ...)
例如:
@BugReport(assignedTo = "Harry", severity=10)
元素的順序無關緊要,下面這個註解和前面那個一樣:
@BugReport(severity=10, assignedTo = "Harry")
如果某個元素的值並未指定,那麼就使用宣告的預設值。
預設值並不是和註解儲存在一起的,它們是動態計算而來的。例如,如果將元素assignedTo的預設值更改為“[]”,然後重新編譯BugReport介面,那麼註解@BugReport(severity=10)將使用這個新的預設值。
簡化註解的使用:
- 標記註解:
如果沒有指定元素,要麼是因為註解中沒有任何元素,要麼是因為所有元素都使用預設值,那麼就不需要使用圓括號,例如:
<span style="font-size:10px;">@BugReport</span>
- 單值註解:
如果一個元素具有特殊的名字value,並且沒有指定其他元素,那麼就可以忽略掉這個元素名及等號這個符號,例如:
<span style="font-size:10px;">public @interface BugReport{
String value();
}</span>
那麼,可以將這個註解寫成如下形式:
<span style="font-size:10px;">@BugReport("Harry")</span>
所有的註解介面隱式地擴充套件自java.lang.annotation.Annotation介面,這個介面是一個正規介面,不是一個註解介面。
無法擴充套件註解介面,所有的註解介面都直接擴充套件自java.lang.annotation.Annotation。
一個專案可以具有多個註解,只要它們屬於不同的型別即可。當註解一個特定項的時候,不能多次使用同一個註解型別,例如:
<span style="font-size:10px;">@BugReport(severity=11)
@BugReport(severity=12)
void myMethod(){... ...}</span>
就是一種編譯期錯誤。
讀取/使用類中定義的註解
示例:
<span style="font-size:10px;">package annotation;
import java.lang.*;
import java.util.*;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
String name();
int id() default 0;
Class<Long> gid();
}
</span>
<span style="font-size:10px;">package annotation;
import java.util.*;
import java.lang.*;
@TestA(name="type", gid=Long.class)
public class UserAnnotation {
@TestA(name="param", id = 1, gid=Long.class)
private Integer age;
@TestA(name="construct", id = 2, gid=Long.class)
public UserAnnotation(){
}
@TestA(name="public method", id = 3, gid=Long.class)
public void a(){
}
@TestA(name="protected method", id = 4, gid= Long.class)
protected void b(){
}
@TestA(name="private method", id = 5, gid = Long.class)
private void c(){
}
}
</span>
<span style="font-size:10px;">package annotation;
import java.lang.*;
import java.util.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
public class ParseAnnotation {
public static void parseTypeAnnotation() throws ClassNotFoundException{
Class clazz = Class.forName("annotation.UserAnnotation");
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation : annotations){
TestA testA = (TestA)annotation;
System.out.println("id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
}
}
public static void parseMethodAnnotation(){
Method[] methods = UserAnnotation.class.getDeclaredMethods();
for (Method method : methods){
boolean hasAnnotation = method.isAnnotationPresent(TestA.class);
if (hasAnnotation){
TestA testA = (TestA)method.getAnnotation(TestA.class);
System.out.println("method = " + method.getName() + " id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
}
}
}
public static void parseConstructAnnotation(){
Constructor[] constructors = UserAnnotation.class.getConstructors();
for (Constructor constructor : constructors){
boolean hasAnnotation = constructor.isAnnotationPresent(TestA.class);
if (hasAnnotation){
TestA testA = (TestA)constructor.getAnnotation(TestA.class);
System.out.println("constructor = " + constructor.getName() + " id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
}
}
}
public static void main(String[] args) throws ClassNotFoundException{
parseTypeAnnotation();
parseMethodAnnotation();
parseConstructAnnotation();
}
}
</span>
執行結果:
<span style="font-size:10px;">id = 0 name = type gid = class java.lang.Long
method = c id = 5 name = private method gid = class java.lang.Long
method = b id = 4 name = protected method gid = class java.lang.Long
method = a id = 3 name = public method gid = class java.lang.Long
constructor = annotation.UserAnnotation id = 2 name = construct gid = class java.lang.Long</span>
相關文章
- Java —— 註解(Annotation)Java
- Java Annotation 註解Java
- Java 註解(Annotation)Java
- Java註解(Annotation)詳解Java
- java-Annotation註解Java
- Java之註解(Annotation)Java
- Java 註解Annotation研究Java
- Java進階(一)Annotation(註解)Java
- Spring(三)——註解方式(Annotation)Spring
- 【framework】spring-註解(annotation)FrameworkSpring
- Java註解(Annotation):請不要小看我!Java
- Java 註解 (Annotation)淺入深出Java
- Android 註解系列之Annotation(二)Android
- 元註解——java.lang.annotation.Target(1.8)Java
- 關於Java註解(annotation)的簡單理解Java
- Java學習之註解Annotation實現原理Java
- hibernate annotation註解方式來處理對映關係
- 「Android」Android開發你需要知道的註解(Annotation)Android
- JAVA ANNOTATION詳解Java
- C# 在PDF中新增墨跡註釋Ink AnnotationC#
- 基於Annotation註解整合SSH框架和基於XML檔案配置Bean整合SSH框架框架XMLBean
- 註解中用於@target的方法annotation/--ElementType.METHOD,ElementType.TYPE對應方法,類介面
- Annotation
- 【mybatis annotation】資料層框架應用--Mybatis(二) 基於註解實現資料的CRUDMyBatis框架
- JDK6.0的新特性之六:插入式註解處理API(Pluggable Annotation Processing API)JDKAPI
- java annotationJava
- Java自定義Annotation,通過反射解析AnnotationJava反射
- Java建立AnnotationJava
- 自定義Annotation
- JUnit basic annotation
- java 的annotationJava
- JAVA-註解(2)-自定義註解及反射註解Java反射
- 註解專題(一)Java元註解,內建註解Java
- java反射——反射AnnotationJava反射
- Annotation for ANDROID ---FirstAndroid
- mark mybatis annotation drivenMyBatis
- Java註解-後設資料、註解分類、內建註解和自定義註解Java
- Spring5:@Autowired註解、@Resource註解和@Service註解Spring