註解並不是第一次看到,類似於見過最多的 @Override
【遇】
BaseActivity中實現了 IGetPageName 接口,接口中 定義了 getPageName方法,添加 @PageName 註解,MainActivity中重寫BaseActivity中的 getPageName 方法並設置返回值,這裏達到了返回值只能設置爲 PageName枚舉中值的效果,而枚舉使用靜態常量+@StringDef 的方法定義。
@PageName 自定義註解,@StringDef (androidx.annotation包內)
BaseActivity.java
IGetPageName.java
PageName.java
MainActivity.java
【問】
註解是什麼,註解有什麼作用?
在什麼情況下會想到要使用註解?
【知】
參考博文:Java Annotation認知(包括框架圖、詳細介紹、示例說明) - 如果天空不死 - 博客園 (cnblogs.com)
1、 Java Annotation是JDK5.0引入的一種註釋機制
2、我對於Annotation的理解
ElementType、RetentionPolicy是枚舉,Annotation是一個接口。然後我們由他們創建新的Annotation註解。新的註解,就是通過實現 Annotation的接口,然後再通過@Target、@Retention註解分別來指定ElementType、RetentionPolicy的值,結構圖中1..n表示@Target可以指定多個枚舉值(用來只能註解可以修飾的位置),而@Retention註解就只能指定一個枚舉值(表示註解作用域,保留到的位置)。
①@Target本身也是註解,那麼上面說註解創建時就要通過@Target來修飾Target的註解。所以存在以下代碼
⭐爲什麼@Target能夠修飾 Target Annotation?不是還在創建階段嗎
有關於這個問題,我還沒有答案。有人回答我說,就像遞歸,自己調用自己。對哇,遞歸,我以前爲什麼沒有問,函數爲什麼能夠自己調用自己?(從網上我得出的理解時,方法定義並不分配內存,而是相當於存儲一個方法的指針,調用的時候再去執行具體的方法,所以當它調用自己的時候,它早就已經告訴編譯器,它存在了。爲什麼函數能遞歸調用自己? - 知乎 (zhihu.com))
除了@Target修飾Target,還存在@Target修飾 Retention 創建,@Retention修飾Target創建,這或許有點像在A函數裏面調用B函數,B函數裏面調用A函數。
很難解釋,那麼是否可以跳過Target 創建,把@Target單純看做成對該註解的註解。即我們只需要知道 @Target 只能修飾 ANNOTATION_TYPE(像這種只能修飾註解的註解稱爲元註解),JDK提供了一系列其他的註解,我們可通過註解上方的註解,瞭解這個註解的作用域和作用。
②ElementType枚舉值以及說明
③RetentionPolicy的枚舉值及說明
④元註解:修飾註解的註解,以下四個
@Documented -- @Documented 所標註內容,可以出現在javadoc中。若不設置默認爲否
@Inherited -- @Inherited只能被用來標註“Annotation類型”,它所標註的Annotation具有繼承性。就是使用該Annotation的類的子類也自動繼承該父類的註解。若不設置默認爲否
@Retention -- @Retention只能被用來標註“Annotation類型”,而且它被用來指定Annotation的RetentionPolicy屬性。若不設置默認爲RetentionPolicy.CLASS
@Target -- @Target只能被用來標註“Annotation類型”,而且它被用來指定Annotation的ElementType屬性。若不設置默認爲可作用域任何地方
@Repeatable -- @Repeatable(重複) 用於聲明標記的註解爲可重複類型註解,可以在同一個地方多次使用
⑤其他註解
@SuppressWarnings -- @SuppressWarnings 所標註內容產生的警告,編譯器會對這些警告保持靜默。
@Deprecated -- @Deprecated 所標註內容,不再被建議使用。
3、kotlin中的Annotation 有什麼不同
①元註解不同 @Documented改成 @MustBeDocumented
去掉了@Inherited(查看:Inherited annotations and other reflections enchancements - Support - Kotlin Discussions (kotlinlang.org))
②ElementType名對應AnnotationTarget,RetentionPolicy名對應AnnotationRetention
③@Retention的默認值不同,Java中默認值爲 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對應 Kotlin中AnnotationRetention.BINARY,ElementType.ANNOTATION_TYPE 對應 AnnotationTarget.ANNOTATION_CLASS 但功能類似,改成了更爲可讀名稱
@Retention(AnnotationRetention.SOURCE)
annotation class PageName{
//語法形式上模擬了靜態類的調用方法
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 子類重寫方法是必須加 super.方法名
- @StringDef 由於enum性能問題,使用靜態常量代替enum,開發者在使用時不能很好的找到取值範圍,並且在不知道源碼的情況下可能導致傳值錯誤,於是用@StringDef可以指定常量,編譯器可以給出提示。(Android中不使用枚舉類(enum)替代爲@IntDef @StringDef - 簡書 (jianshu.com))
- 爲什麼enum影響性能?
因爲沒有enum的值都會創建了一個Object對象,佔用內存。
5、爲什麼@PageName能夠限定方法的返回值是PageName內枚舉值
這裏@PageName和@StringDef結合,實際上達到的是枚舉的作用效果,可以方法參數前面,或者方法上方,指定參數的傳值區間和返回值區間。這裏是用作枚舉。
6、有關PermissionX使用註解對是否請求權限的檢查
【註解的作用】
1、編譯檢查
@PageName實際上也是起到這樣的效果、@Override
2、生成對應的幫助文檔