Java注解知識梳理--注解概念知識

Java注解

注解是JDK5引入的一個特性,可以為我們的代碼打上一個標(biāo)記,配合java中的反射會有意想不到的驚喜。我們經(jīng)常用到很多框架都是用到了該特性。所有的注解都繼承于Annotation。

Java 8以前,注解只能在聲明的地方使用(聲明方法、變量、類等),Java 8開始,注解可以在任何地方使用(泛型、拋異常、方法中等),這是因為Java 8 增加了兩種ElementType(下文會介紹)。

  • 備注:代碼基于Android API 26 中的java代碼以及Java 8中的代碼(Mac>>Android studio 3.3.2)。

注解的示例

  • 自定義注解代碼示例:
/**
 * 測試注解
 * TestApplication
 * Created by anonyper on 2019/5/30.
 */
@Retention(RetentionPolicy.RUNTIME)//屬于運(yùn)行時注解
@Target(ElementType.METHOD)//適用于方法注解
public @interface TestAnnotationMethod {
    
    String LabelType() default "default";//注解中LabelType 取值
}
  • 系統(tǒng)內(nèi)置注解代碼示例:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  • 使用代碼示例:
public class RachelApplication extends Application {
    //系統(tǒng)注解
    @Override
    public void onCreate() {
        super.onCreate();
        Intent intent = new Intent(this, LocationService.class);
        startService(intent);
    }

    //自定義注解
    @TestAnnotationMethod(LabelType = "Wifi")
    public void testMethod() {

    }
}

注解基本語法介紹

從示例中可以看到,使用@interface即可標(biāo)示這是一個注解,一個注解包括元注解注解屬性兩部分。下面我們分別來介紹元注解、Java內(nèi)置的常用注解以及注解屬性。

注解屬性

注解起到一種標(biāo)記作用,有的時候我們需要給定不同的屬性,比如上面的String LabelType() default "default";//注解中LabelType 取值這段代碼。這是用來給一個注解指定一個屬性。比如我們用到的@Target注解,里面的值是一個枚舉,代表著該注解的不用使用范圍。再比如,我們自定義一個注解用于標(biāo)示人物身份,那么身份的值就可能包含:老師、學(xué)生、企業(yè)家、律師、醫(yī)生等等。

注解的屬性也可以叫做成員變量(注解內(nèi)不能有方法的),定義屬性的時候需要用無形參的方式來聲明,并且方法名代表變量名字,返回值代表屬性的類型(屬性類型可為:8種基本類型(byte字節(jié)型、short短正型、int整型、long長整型、float單精度浮點型、double雙精度浮點型、boolean布爾型、char字符型)、Class類型、String、枚舉、注解以及他們的數(shù)組)。

  • 屬性的使用:
@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時注解
@Target(ElementType.TYPE)//適用于方法注解
public @interface TestAnnotation {

    String LabelType() default "guanwang" ;
}

//使用:
@TestAnnotation(LabelType = "Wifi")
public class RachelApplication{
  
}

//或者
@TestAnnotation//默認(rèn)是guanwang
public class RachelApplication{
  
}

//或者
@TestAnnotation()//默認(rèn)是guanwang
public class RachelApplication{
  
}
  • value

value算是一個特殊的屬性,如果一個注解中只有value屬性需要設(shè)置(沒有其他屬性或其他屬性有默認(rèn)值),在設(shè)置時value=可以省略。

@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時注解
@Target(ElementType.TYPE)//適用于方法注解
public @interface TestAnnotation {

    String LabelType() default "guanwang" ;
    String value();
}
//使用
@TestAnnotation("GPRS")
public class RachelApplication{
  
}
  • 其他類型屬性
@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時注解
@Target(ElementType.TYPE)//適用于方法注解
public @interface TestAnnotation {

    int index() default 1;//int 類型

    boolean flag() default false;//布爾類型

    String LabelType() default "guanwang";//字符串

    int[] arrayint() default {1, 2, 3, 4};//數(shù)組

    ElementType elementType() default ElementType.TYPE;//枚舉類型 用了ElementType做示例

    Target target() default @Target(ElementType.TYPE); //注解類型 這里用了Target做示例

    Class<?> classType() default Integer.class;//class類型
  
    String value();
}

元注解

元注解就是可以標(biāo)記注解的注解,我們在聲明注解使用的范圍@Target,生存周期@Retention等我們常用的,還有一些諸如@Documented、@Inherited、@Repeatable等元注解,我們接下來一一說明他們各自的含義:

@Target

限定注解的作用范圍,比如方法、類、變量、等,具體如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Target {
    ElementType[] value();
}

//ElementType 代碼如下
public enum ElementType {
    ANNOTATION_TYPE,//可以用在另一個注解上(自定義元注解)
    CONSTRUCTOR,//可以用于構(gòu)造方法上
    FIELD,//可以用于字段聲明上,包括枚舉上
    LOCAL_VARIABLE,//可以用于局部變量上
    METHOD,//可以用于方法上
    PACKAGE,//可以用于包聲明上
    PARAMETER,//可以用于參數(shù)聲明上
    TYPE,//可以用于類、接口、枚舉聲明上
    TYPE_PARAMETER,//表示注解能寫在類型變量的聲明語句中。1.8版本加入的 網(wǎng)上的示例比如
    //List<Integer> list = new @Save ArrayList<>(); 但是我在測試過程中報錯(Mac AndroidStudio 3.3.2 Android 26 java 1.8 ),唯一測試可用的地方:public class Book<@TestAnnotation T>
    TYPE_USE;//表示注解能寫在使用類型的任何語句中 1.8版本加入 如
    /**
        public class Book<@TestAnnotation T> {
            List<Integer> list = new @TestAnnotation ArrayList<>();
            @TestAnnotation int index = 10;//默認(rèn)10本書
            public @TestAnnotation int getIndex() {
            return 1;
            }
        }
    */

    private ElementType() {
    }
}

Java 8 新增的兩個類型注解的作用是用來強(qiáng)健java代碼,配合第三方工具(如Checker Framework)做強(qiáng)類型檢查,可以在編譯期檢測出異常(如UnsupportedOperationException、NullPointerException異常等),避免了程序在運(yùn)行時才拋出錯誤,這就是類型注解的主要作用。

@Retention

用來標(biāo)示該注解的生存周期,比如運(yùn)行時注解、編譯時注解等。

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

//RetentionPolicy 代碼如下
public enum RetentionPolicy {
    CLASS,//標(biāo)示注解只被保留到編譯的時候,不會被加載到JVM中
    RUNTIME,//標(biāo)示注解可以保留到運(yùn)行時,會被加載到JVM中
    SOURCE;//標(biāo)示注解只是在源代碼階段,在編譯前會被忽略

    private RetentionPolicy() {
    }
}

@Documented

標(biāo)示將注解的元素包含到j(luò)avadoc中。(我們可以把我們的代碼生成API文檔的哦)

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

@Inherited

標(biāo)示改注解可以被繼承,如果一個父類使用該注解,子類沒有做其他注解時,默認(rèn)繼承了父類的注解。

@Inherited //該注解可以被繼承
@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時注解
@Target(ElementType.TYPE)//適用于類注解
public @interface TestAnnotationType {
}

//父類使用注解,該注解有Inherited標(biāo)示
@TestAnnotationType
class ParentClass {

}

//子類默認(rèn)繼承父類的注解
public class ChildClass extends ParentClass {

}

@Repeatable(Java 8增加的)

標(biāo)示該注解在一個地方可重復(fù)使用,可以取不同的值,如一個人的身份可以是律師,他還兼職老師的工作。需要傳入一個繼承注解的類來作為其容器。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Repeatable {
    Class<? extends Annotation> value();
}

//使用方法:

//注解容器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Identitys {
    Identity[] value();//必須有一個方法名為 value 返回的類型用的是使用Repeatable的注解
}

//聲明可重復(fù)
@Repeatable(Identitys.class)//容器類是Identitys
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Identity {
    String label();
}

//具體使用
@Identity(label = "student")
@Identity(label = "teacher")
public class TestRepeatable {

}

Java內(nèi)置常用注解

我們在繼承一個類,子類重新父類方法時是不是用到@Override,在看到老版本廢棄的方法時,是否看到@Deprecated呢,這些都是Java內(nèi)置的注解,常用的有:

@Override

標(biāo)示子類復(fù)寫了父類的方法用到的修飾。防止父類方法名改變時,子類方法忘記做對應(yīng)調(diào)整。

@Deprecated

標(biāo)示過時的元素,雖然可以調(diào)用,但不建議使用的意思,使用的時候,在IDE上會顯示一條灰色的線。

@SuppressWarnings

阻止編譯器對被標(biāo)記方法、類發(fā)出警告,里面需要傳入阻止警告的哪些類型,常用的:all(所有警告)、unchecked(沒有進(jìn)行類型檢查操作的警告)、unused(沒有使用過的代碼警告),deprecation(使用過期方法)。所以在調(diào)用過時方法的方法前面加上@SuppressWarnings("deprecation"),那條灰色就不會顯示了。

具體SuppressWarnings類型值的解釋,可以自行百度。

@SafeVarargs (Java 7新增)

Java SE 5中引入的可變形參加上Java編譯器的機(jī)制,導(dǎo)致在使用可變形參的時候,編譯器會產(chǎn)生一個未經(jīng)檢查的警告,SafeVarargs注解就可以忽略這些警告。SafeVarargs注解只能用在參數(shù)長度可變的靜態(tài)方法(或用final修飾)或構(gòu)造方法上,否則會出現(xiàn)編譯錯誤。(這些只是屏蔽了編譯時的警告,如果類型轉(zhuǎn)化錯誤,在運(yùn)行時還會報錯的)。

SafeVarargs產(chǎn)生由來介紹

@FunctionalInterface(Java 8新增)

該注解標(biāo)示該類是一個函數(shù)式的接口,就是里面除了Object類中public修飾的方法外只有一個抽象方法。比如 View.OncClickListener,Runnable等都可以使用FunctionalInterface標(biāo)記一下。這些函數(shù)式接口可以使用lambda表達(dá)式來編寫。

注解的使用

上面介紹了注解的基本知識,我們學(xué)會了如何對一個元素用注解進(jìn)行標(biāo)記,那么接下來我們就要考慮標(biāo)記之后如何識別呢?這些內(nèi)容因為篇幅原因,我們就另開一篇分析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容