Android Annotation ——XArch
注解并不是第一次看到,類似于見(jiàn)過(guò)最多的 @Override
【遇】
BaseActivity中實(shí)現(xiàn)了 IGetPageName 接口,接口中 定義了 getPageName方法,添加 @PageName 注解,MainActivity中重寫(xiě)B(tài)aseActivity中的 getPageName 方法并設(shè)置返回值,這里達(dá)到了返回值只能設(shè)置為 PageName枚舉中值的效果,而枚舉使用靜態(tài)常量+@StringDef 的方法定義。
@PageName 自定義注解,@StringDef (androidx.annotation包內(nèi))
BaseActivity.java

IGetPageName.java

PageName.java

MainActivity.java

【問(wèn)】
注解是什么,注解有什么作用?
在什么情況下會(huì)想到要使用注解?
【知】
參考博文:Java Annotation認(rèn)知(包括框架圖、詳細(xì)介紹、示例說(shuō)明) - 如果天空不死 - 博客園 (cnblogs.com)
1、 Java Annotation是JDK5.0引入的一種注釋機(jī)制
2、我對(duì)于Annotation的理解

ElementType、RetentionPolicy是枚舉,Annotation是一個(gè)接口。然后我們由他們創(chuàng)建新的Annotation注解。新的注解,就是通過(guò)實(shí)現(xiàn) Annotation的接口,然后再通過(guò)@Target、@Retention注解分別來(lái)指定ElementType、RetentionPolicy的值,結(jié)構(gòu)圖中1..n表示@Target可以指定多個(gè)枚舉值(用來(lái)只能注解可以修飾的位置),而@Retention注解就只能指定一個(gè)枚舉值(表示注解作用域,保留到的位置)。
①@Target本身也是注解,那么上面說(shuō)注解創(chuàng)建時(shí)就要通過(guò)@Target來(lái)修飾Target的注解。所以存在以下代碼

?為什么@Target能夠修飾 Target Annotation?不是還在創(chuàng)建階段嗎
有關(guān)于這個(gè)問(wèn)題,我還沒(méi)有答案。有人回答我說(shuō),就像遞歸,自己調(diào)用自己。對(duì)哇,遞歸,我以前為什么沒(méi)有問(wèn),函數(shù)為什么能夠自己調(diào)用自己?(從網(wǎng)上我得出的理解時(shí),方法定義并不分配內(nèi)存,而是相當(dāng)于存儲(chǔ)一個(gè)方法的指針,調(diào)用的時(shí)候再去執(zhí)行具體的方法,所以當(dāng)它調(diào)用自己的時(shí)候,它早就已經(jīng)告訴編譯器,它存在了。為什么函數(shù)能遞歸調(diào)用自己? - 知乎 (zhihu.com))
除了@Target修飾Target,還存在@Target修飾 Retention 創(chuàng)建,@Retention修飾Target創(chuàng)建,這或許有點(diǎn)像在A函數(shù)里面調(diào)用B函數(shù),B函數(shù)里面調(diào)用A函數(shù)。
很難解釋,那么是否可以跳過(guò)Target 創(chuàng)建,把@Target單純看做成對(duì)該注解的注解。即我們只需要知道 @Target 只能修飾 ANNOTATION_TYPE(像這種只能修飾注解的注解稱為元注解),JDK提供了一系列其他的注解,我們可通過(guò)注解上方的注解,了解這個(gè)注解的作用域和作用。
②ElementType枚舉值以及說(shuō)明

③RetentionPolicy的枚舉值及說(shuō)明

④元注解:修飾注解的注解,以下四個(gè)
@Documented -- @Documented 所標(biāo)注內(nèi)容,可以出現(xiàn)在javadoc中。若不設(shè)置默認(rèn)為否
@Inherited -- @Inherited只能被用來(lái)標(biāo)注“Annotation類型”,它所標(biāo)注的Annotation具有繼承性。就是使用該Annotation的類的子類也自動(dòng)繼承該父類的注解。若不設(shè)置默認(rèn)為否
@Retention -- @Retention只能被用來(lái)標(biāo)注“Annotation類型”,而且它被用來(lái)指定Annotation的RetentionPolicy屬性。若不設(shè)置默認(rèn)為RetentionPolicy.CLASS
@Target -- @Target只能被用來(lái)標(biāo)注“Annotation類型”,而且它被用來(lái)指定Annotation的ElementType屬性。若不設(shè)置默認(rèn)為可作用域任何地方
@Repeatable -- @Repeatable(重復(fù)) 用于聲明標(biāo)記的注解為可重復(fù)類型注解,可以在同一個(gè)地方多次使用
⑤其他注解
@SuppressWarnings -- @SuppressWarnings 所標(biāo)注內(nèi)容產(chǎn)生的警告,編譯器會(huì)對(duì)這些警告保持靜默。
@Deprecated -- @Deprecated 所標(biāo)注內(nèi)容,不再被建議使用。
3、kotlin中的Annotation 有什么不同
①元注解不同 @Documented改成 @MustBeDocumented
去掉了@Inherited(查看:Inherited annotations and other reflections enchancements - Support - Kotlin Discussions (kotlinlang.org))
②ElementType名對(duì)應(yīng)AnnotationTarget,RetentionPolicy名對(duì)應(yīng)AnnotationRetention
③@Retention的默認(rèn)值不同,Java中默認(rèn)值為 RetentionPolicy.CLASS,Kotlin中是AnnotationRetention.RUNTIME
package kotlin.annotation
import kotlin.annotation.AnnotationTarget.*
/**
* Contains the list of code elements which are the possible annotation targets
*/
public enum class AnnotationTarget {
/** Class, interface or object, annotation class is also included */
CLASS,
/** Annotation class only */
ANNOTATION_CLASS,
/** Generic type parameter */
TYPE_PARAMETER,
/** Property */
PROPERTY,
/** Field, including property's backing field */
FIELD,
/** Local variable */
LOCAL_VARIABLE,
/** Value parameter of a function or a constructor */
VALUE_PARAMETER,
/** Constructor only (primary or secondary) */
CONSTRUCTOR,
/** Function (constructors are not included) */
FUNCTION,
/** Property getter only */
PROPERTY_GETTER,
/** Property setter only */
PROPERTY_SETTER,
/** Type usage */
TYPE,
/** Any expression */
EXPRESSION,
/** File */
FILE,
/** Type alias */
@SinceKotlin("1.1")
TYPEALIAS
}
/**
* Contains the list of possible annotation's retentions.
*
* Determines how an annotation is stored in binary output.
*/
public enum class AnnotationRetention {
/** Annotation isn't stored in binary output */
SOURCE,
/** Annotation is stored in binary output, but invisible for reflection */
BINARY,
/** Annotation is stored in binary output and visible for reflection (default retention) */
RUNTIME
}
/**
* This meta-annotation indicates the kinds of code elements which are possible targets of an annotation.
*
* If the target meta-annotation is not present on an annotation declaration, the annotation is applicable to the following elements:
* [CLASS], [PROPERTY], [FIELD], [LOCAL_VARIABLE], [VALUE_PARAMETER], [CONSTRUCTOR], [FUNCTION], [PROPERTY_GETTER], [PROPERTY_SETTER].
*
* @property allowedTargets list of allowed annotation targets
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
@MustBeDocumented
public annotation class Target(vararg val allowedTargets: AnnotationTarget)
/**
* This meta-annotation determines whether an annotation is stored in binary output and visible for reflection. By default, both are true.
*
* @property value necessary annotation retention (RUNTIME, BINARY or SOURCE)
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class Retention(val value: AnnotationRetention = AnnotationRetention.RUNTIME)
/**
* This meta-annotation determines that an annotation is applicable twice or more on a single code element
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class Repeatable
/**
* This meta-annotation determines that an annotation is a part of public API and therefore should be included in the generated
* documentation for the element to which the annotation is applied.
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
public annotation class MustBeDocumented
④定義Annotation的方法不同
java中使用 @interface ,kotlin 中使用 annotation class。
⑤枚舉中的部分字段就不同。比如Java中RetentionPolity.CLASS對(duì)應(yīng) Kotlin中AnnotationRetention.BINARY,ElementType.ANNOTATION_TYPE 對(duì)應(yīng) AnnotationTarget.ANNOTATION_CLASS 但功能類似,改成了更為可讀名稱
@Retention(AnnotationRetention.SOURCE)
annotation class PageName{
//語(yǔ)法形式上模擬了靜態(tài)類的調(diào)用方法
companion object{
const val MAIN = "main"
const val HOME = "home"
const val ACGN = "acgn"
const val SMALL_VIDEO = "small_video"
const val GOLD = "gold"
const val MINE = "mine"
const val ABOUT = "about"
const val DISCOVERY = "discovery"
}
}
4、Androidx中的一些注解(androidx.annotation | Android Developers (google.cn))
- @CallSuper 子類重寫(xiě)方法是必須加 super.方法名
- @StringDef 由于enum性能問(wèn)題,使用靜態(tài)常量代替enum,開(kāi)發(fā)者在使用時(shí)不能很好的找到取值范圍,并且在不知道源碼的情況下可能導(dǎo)致傳值錯(cuò)誤,于是用@StringDef可以指定常量,編譯器可以給出提示。(Android中不使用枚舉類(enum)替代為@IntDef @StringDef - 簡(jiǎn)書(shū) (jianshu.com))

- 為什么enum影響性能?
因?yàn)闆](méi)有enum的值都會(huì)創(chuàng)建了一個(gè)Object對(duì)象,占用內(nèi)存。
5、為什么@PageName能夠限定方法的返回值是PageName內(nèi)枚舉值
這里@PageName和@StringDef結(jié)合,實(shí)際上達(dá)到的是枚舉的作用效果,可以方法參數(shù)前面,或者方法上方,指定參數(shù)的傳值區(qū)間和返回值區(qū)間。這里是用作枚舉。
6、有關(guān)PermissionX使用注解對(duì)是否請(qǐng)求權(quán)限的檢查
【注解的作用】
1、編譯檢查
@PageName實(shí)際上也是起到這樣的效果、@Override
2、生成對(duì)應(yīng)的幫助文檔

浙公網(wǎng)安備 33010602011771號(hào)