【框架基礎】:全面解析Java註解(一)
Java註解概述
要了解Java註解要先知道Java的反射,反射是執行時獲取類的成員,註解也是類的成員,以此達到動態編碼的效
果,多用在框架,或者使用框架時候添加註解讓框架呼叫。
註解定義:註解(Annotation),也叫元資料。Java提供了一種原程式中的元素關聯任何資訊和任何元資料的途
徑和方法,一種程式碼級別的說明。它是JDK1.5及以後版本引入的一個特性,與類、介面、列舉是在同一個層次。它可
以宣告在包、類、欄位、方法、區域性變數、方法引數等的前面,用來對這些元素進行說明,註釋。
Annotation(註解)是JDK1.5及以後版本引入的。它可以用於建立文件,跟蹤程式碼中的依賴性,甚至執行基本編譯
時檢查。註解是以‘@註解名’在程式碼中存在的,根據註解引數的個數,我們可以將註解分為:標記註解、單值注
解、完整註解三類。它們都不會直接影響到程式的語義,只是作為註解(標識)存在,我們可以通過反射機制程式設計實
現對這些元資料(用來描述資料的資料)的訪問。另外,你可以在編譯時選擇程式碼裡的註解是否只存在於原始碼級,
或者它也能在class檔案、或者執行時中出現(SOURCE/CLASS/RUNTIME)。
註解的作用
如果要對於註解的作用進行分類,還沒有明確的定義,不過我們可以根據它所起的作用,大致可分為三類:
編寫文件:通過程式碼裡標識的元資料生成文件【生成文件doc文件】
程式碼分析:通過程式碼裡標識的元資料對程式碼進行分析【使用反射】
編譯檢查:通過程式碼裡標識的元資料讓編譯器能夠實現基本的編譯檢查【Override】
為什麼學習註解
1、能夠讀懂別人寫的程式碼,特別是框架相關的程式碼,增加程式碼的閱讀性;
2、讓程式設計更加簡潔,程式碼更加清晰,理清自己的思路;
3、生成API文件;
Java中的常見註解
JDK內建註解
@Override
它的作用是對覆蓋超類中方法的方法進行標記,如果被標記的方法並沒有實際覆蓋超類中的方法,則編譯器會發
出錯誤警告。下面的例子是實現類Child實現了介面Person的方法 使用了@Override。
package com.demo.annotation;
/**
* 測試@Override註解
* @author Administrator
* @date 2016年12月9日
*/
public interface Person {
public String name();
public int age();
public void sing();
}
class Child implements Person {
@Override
public String name() {
// TODO Auto-generated method stub
return null;
}
@Override
public int age() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void sing() {
// TODO Auto-generated method stub
}
}
@Deprecated
它的作用是對不應該再使用的方法添加註解,當程式設計人員使用這些方法時,將會在編譯時顯示提示資訊,它與
javadoc裡的@deprecated標記有相同的功能,準確的說,它還不如javadoc @deprecated,因為它不支援引數,
使用@Deprecated的示例程式碼示例如下:
package com.demo.annotation;
/**
* 測試@Deprecated註解
* @author Administrator
* @date 2016年12月9日
*/
public interface Person {
public String name();
public int age();
@Deprecated
public void sing();
}
class Child implements Person {
@Override
public String name() {
// TODO Auto-generated method stub
return null;
}
@Override
public int age() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void sing() {
// TODO Auto-generated method stub
}
}
class Test {
@SuppressWarnings("deprecation")
public void sing(){
Person person = new Child();
person.sing();//sing()方法已經過時
}
}
Person介面使用了@Deprecated修飾了一個已經過時的方法,此時強行呼叫超類繼承來的方法就會有個程式碼過
時的橫線,並且報一個程式碼過時的警告,但不會影響正常使用。如果要去掉警告可以使用
@suppressWarings("deprecation") 來忽略這個警告。
@SuppressWarnings
其引數有:
deprecation:使用了過時的類或方法時的警告
unchecked:執行了未檢查的轉換時的警告
fallthrough:當 switch 程式塊直接通往下一種情況而沒有 break 時的警告
path:在類路徑、原始檔路徑等中有不存在的路徑時的警告
serial:當在可序列化的類上缺少serialVersionUID 定義時的警告
finally :任何 finally 子句不能正常完成時的警告
all:關於以上所有情況的警告
這裡的演示在上面已經出現過。
常見的第三方註解
在這裡只是簡單的演示一下,在學習框架的過程中再詳細說明。
按照過去的方式就是寫一個配置檔案:
使用註解方式不再使用配置檔案:
Java註解的分類
按照執行機制分類
原始碼註解:註解只在原始碼中存在,編譯成.class檔案就不存在了;
編譯時註解:註解在原始碼和.class檔案中都存在,比如@SuppressWarnings、@Override和@Deprecated只在
編譯時刻起作用;
執行時註解:原始碼、編譯後以及執行時都存在的註解,在執行階段還起作用,甚至會影響執行邏輯的註解,比如
spring框架的@Autowired註解。
按照來源分類
來自JDK的註解:@SuppressWarnings、@Override和@Deprecated
來自第三方的註解:比如spring框架的@Autowired註解
自定義註解:我們自己定義的註解。
元註解
註解的註解:自定義註解中比較常見。
Java自定義註解
先來看一個模板:
自定義註解語法要求
1)使用@Interface關鍵字定義註解;
2)成員以無參無異常方式宣告;
3)可以用default為成員指定一個預設值;
4)成員型別是受限的,合法的型別包括原始型別及String、Class、Annotation、Enumeration;
5)如果註解只有一個成員,則成員必須取名為value(),在使用時可以忽略成員名和賦值號(=);
6)註解類可以沒有成員,沒有成員的註解稱為標識註解;
註解的註解(元註解)
@Target({ElementType.METHOD,ElementType.TYPE})
CONSTRUCTOR:構造方法宣告
FIELD:欄位宣告
LOACL_VARIABLE:區域性變數宣告
METHOD:方法宣告
PACKAGE:包宣告
PARAMETER:引數宣告
TYPE:類或者介面宣告
@Retention(RetentionPolicy.RUNTIME)
SOURCE:只在原始碼顯示,編譯時會丟棄
CLASS:編譯時會記錄到class中,執行時忽略
RUNTIME:執行時存在,可以通過反射讀取
@Inherited
允許子類繼承
@Documented
生成javadoc時會包含註解
使用自定義註解
使用註解的語法:@<註解名>(<成員名1>=<成員值1>,<成員名2>=<成員值2>,...)
一個簡單的例子:
定義@Description註解:
package com.demo.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String desc();
String author();
int age() default 18;
}
使用註解:
package com.demo.annotation;
@Description(desc="I am class annotation",author="Mooc boy",age=18)
public class AnnotationTest {
@Description(desc="I am method annotation",author="Mooc boy",age=18)
public String eyeColor(){
return "red";
}
}
@Description註解在eyeColor()方法上使用,可以在類或者介面上使用
解析註解
概念:通過反射獲取類,函式或成員上的執行時註解資訊,從而實現動態控制控制程式執行的邏輯。
對於@RetentionRetention表示作用範圍,我們知道:SOURCE表示只在原始碼顯示,編譯時會丟棄;
CLASS表示編譯時會記錄到class中,執行時忽略;RUNTIME表示執行時存在,可以通過反射讀取。前兩個都不會顯
示結果,只有最後一個會顯示結果。
一個例子:
package com.demo.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* 解析註解
* @author Administrator
* @date 2016年12月9日
*/
public class Demo {
public static void main(String[] args) {
//1.使用類載入器載入類
try {
Class< ?> clazz = Class.forName("com.demo.annotation.AnnotationTest");
//2.找到類上面的註解
boolean flag1 = clazz.isAnnotationPresent(Description.class);
if(flag1){
//3.拿到註解例項
Description description1 = (Description)clazz.getAnnotation(Description.class);
System.out.println(description1.desc());
System.out.println(description1.author());
System.out.println(description1.age());
}
//4.解析找到方法上的註解
Method[] methods = clazz.getMethods();
for (Method method : methods) {
boolean flag2 = method.isAnnotationPresent(Description.class);
if(flag2){
//5.拿到註解例項
Description description2 = (Description)method.getAnnotation(Description.class);
System.out.println(description2.desc());
System.out.println(description2.author());
System.out.println(description2.age());
}
}
//另外一種解析方法
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if(annotation instanceof Description){
Description description3 = (Description)annotation;
System.out.println(description3.desc());
System.out.println(description3.author());
System.out.println(description3.age());
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
執行結果:
關於@Inherited元註解
父子類繼承註解這塊分兩種情況,一個是註解定義了@Inherited,一個是沒定義。在每種情況中又分類上的注
解,子類實現父類抽象方法,繼承了父類方法,覆蓋了父類方法這四種情況,具體繼承規則如下:
編寫自定義註解時未寫@Inherited的執行結果:
子類的類上能否繼承到父類的類上的註解? 否
子類方法,實現了父類上的抽象方法,這個方法能否繼承到註解? 否
子類方法,繼承了父類上的方法,這個方法能否繼承到註解? 能
子類方法,覆蓋了父類上的方法,這個方法能否繼承到註解? 否
編寫自定義註解時寫了@Inherited的執行結果:
子類的類上能否繼承到父類的類上的註解? 能
子類方法,實現了父類上的抽象方法,這個方法能否繼承到註解? 否
子類方法,繼承了父類上的方法,這個方法能否繼承到註解? 能
子類方法,覆蓋了父類上的方法,這個方法能否繼承到註解? 否
僅供參考!