Java 注解(Annotation)又稱 Java 標(biāo)注斗忌,是 JDK5.0 引入的一種注釋機(jī)制质礼。 注解是元數(shù)據(jù)的一種形式,提供有關(guān)于程序但不屬于程序本身的數(shù)據(jù)织阳。注解對它們注解的代碼的操作沒有直接影響眶蕉。
注解本身沒有任何意義,單獨的注解就是一種注釋唧躲,他需要結(jié)合其他如反射造挽、插樁等技術(shù)才有意義。
注解聲明
聲明一個注解類型
Java中所有的注解弄痹,默認(rèn)實現(xiàn) Annotation
接口:
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
與聲明一個"Class"
不同的是饭入,注解的聲明使用 @interface
關(guān)鍵字。一個注解的聲明如下:
public @interface Bala{
}
元注解
定義注解時肛真,注解類也能夠使用其他的注解聲明谐丢。對注解類型進(jìn)行注解的注解類,我們稱之為 meta-annotation(元注解)蚓让。一般的乾忱,我們在定義自定義注解時,需要指定的元注解有兩個 :
另外還有@Documented 與 @Inherited元注解历极,前者用于被javadoc工具提取成文檔窄瘟,后者表示允許子類繼承父類中定義的注解。
@Target
注解標(biāo)記另一個注解执解,以限制可以應(yīng)用注解的Java元素類型寞肖。目標(biāo)注解指定以下元素類型之一作為其值:
-
ElementType.ANNOTATION_TYPE
可以應(yīng)用于注解類型纲酗。 -
ElementType.CONSTRUCTOR
可以應(yīng)用于構(gòu)造函數(shù)衰腌。 -
ElementType.FIELD
可以應(yīng)用于字段或?qū)傩浴?/li> -
ElementType.LOCAL_VARIABLE
可以應(yīng)用于局部變量。 -
ElementType.METHOD
可以應(yīng)用于方法級注解觅赊。 -
ElementType.PACKAGE
可以應(yīng)用于包聲明右蕊。 -
ElementType.PARAMETER
可以應(yīng)用于方法的參數(shù)。 -
ElementType.TYPE
可以應(yīng)用于類的任何元素吮螺。
@Retention
注解指定標(biāo)記注解的存儲方式:
-
RetentionPolicy.SOURCE
- 標(biāo)記的注解僅保留在源級別中饶囚,并被編譯器忽略帕翻。 -
RetentionPolicy.CLASS
- 標(biāo)記的注解在編譯時由編譯器保留,但 Java 虛擬機(jī)(JVM)會忽略萝风。 -
RetentionPolicy.RUNTIME
- 標(biāo)記的注解由 JVM 保留嘀掸,因此運(yùn)行時環(huán)境可以使用它。
@Retention 三個值中 SOURCE < CLASS < RUNTIME规惰,即CLASS包含了SOURCE睬塌,RUNTIME包含SOURCE、CLASS歇万。
示例:
//@Target(ElementType.TYPE) 只能在類上標(biāo)記該注解
@Target({ElementType.TYPE,ElementType.FIELD}) // 允許在類與類屬性上標(biāo)記該注解
@Retention(RetentionPolicy.SOURCE) //注解保留在源碼中
public @interface Bala {
}
級別 | 技術(shù) | 說明 |
---|---|---|
源碼 | APT | 在編譯期能夠獲取注解與注解聲明的類包括類中所有成員信息揩晴,一般用于生成額外的輔助類。 |
字節(jié)碼 | 字節(jié)碼增強(qiáng) | 在編譯出Class后贪磺,通過修改Class數(shù)據(jù)以實現(xiàn)修改代碼邏輯目的硫兰。對于是否需要修改的區(qū)分或者修改為不同邏輯的判斷可以使用注解。 |
運(yùn)行時 | 反射 | 在程序運(yùn)行期間寒锚,通過反射技術(shù)動態(tài)獲取注解與其元素劫映,從而完成不同的邏輯判定。 |
注解類型元素
在上文元注解中刹前,允許在使用注解時傳遞參數(shù)苏研。我們也能讓自定義注解的主體包含 annotation type element (注解類型元素) 聲明,它們看起來很像方法腮郊,可以定義可選的默認(rèn)值摹蘑。
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Bala {
String value(); //無默認(rèn)值
int age() default 1; //有默認(rèn)值
}
注意:在使用注解時,如果定義的注解中的類型元素?zé)o默認(rèn)值轧飞,則必須進(jìn)行傳值衅鹿。
@Bala("帥") //如果只存在value元素需要傳值的情況,則可以省略:元素名=
@Bala(value="帥",age = 2)
int i;
注解應(yīng)用場景
按照 @Retention 元注解定義的注解存儲方式过咬,注解可以被在三種場景下使用:
SOURCE
RetentionPolicy.SOURCE
大渤,作用于源碼級別的注解,可提供給IDE語法檢查掸绞、APT等場景使用泵三。
在類中使用 SOURCE
級別的注解,其編譯之后的class中會被丟棄衔掸。
IDE語法檢查
例如:@DrawableRes
public static void setDrawable(@DrawableRes int id) { }
在Android開發(fā)中烫幕, support-annotations
與 androidx.annotation
中均有提供 @IntDef
注解,此注解的定義如下:
@Retention(SOURCE) //源碼級別注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
int[] value() default {};
boolean flag() default false;
boolean open() default false;
}
Java中Enum(枚舉)的實質(zhì)是特殊單例的靜態(tài)成員變量敞映,在運(yùn)行期所有枚舉類作為單例较曼,全部加載到內(nèi)存中。比常量多5到10倍的內(nèi)存占用振愿。
此注解的意義在于能夠取代枚舉捷犹,實現(xiàn)如方法入?yún)⑾拗啤?/p>
如:我們定義方法test
弛饭,此方法接收參數(shù) teacher 需要在:A、B 中選擇一個萍歉。如果使用枚舉能夠?qū)崿F(xiàn)為:
public enum Teacher{
A , B
}
public void test(Teacher teacher) {
}
而現(xiàn)在為了進(jìn)行內(nèi)存優(yōu)化侣颂,我們現(xiàn)在不再使用枚舉,則方法定義為:
public static final int A = 1;
public static final int B = 2;
public void test(int teacher) {
}
然而此時枪孩,調(diào)用 test
方法由于采用基本數(shù)據(jù)類型int
横蜒,將無法進(jìn)行類型限定。此時使用@IntDef
增加自定義注解:
public static final int A = 1;
public static final int B = 2;
@IntDef(value = {A, B}) //限定為A销凑,B
@Target(ElementType.PARAMETER) //作用于參數(shù)的注解
@Retention(RetentionPolicy.SOURCE) //源碼級別注解
public @interface Teacher {
}
public void test(@Teacher int teacher) {
}
此時丛晌,我們再去調(diào)用 test
方法,如果傳遞的參數(shù)不是 A 或者 B 則會顯示 Inspection 警告(編譯不會報錯)斗幼。
- 可以修改此類語法檢查級別:
在AS -> Setting -> Editor -> Inspections -> 右邊界面搜索Incorrect constant
修改Severity等級
以上注解均為 SOURCE
級別澎蛛,本身IDEA/AS 就是由Java開發(fā)的,工具實現(xiàn)了對Java語法的檢查蜕窿,借助注解能對被注解的特定語法進(jìn)行額外檢查谋逻。
APT注解處理器
APT全稱為:"Anotation Processor Tools",意為注解處理器桐经。顧名思義毁兆,其用于處理注解。編寫好的Java源文
件阴挣,需要經(jīng)過 javac
的編譯气堕,翻譯為虛擬機(jī)能夠加載解析的字節(jié)碼Class文件。注解處理器是 javac
自帶的一個工具畔咧,用來在編譯時期掃描處理注解信息茎芭。你可以為某些注解注冊自己的注解處理器。 注冊的注解處理器由 javac
調(diào)起誓沸,并將注解信息傳遞給注解處理器進(jìn)行處理梅桩。
注解處理器是對注解應(yīng)用最為廣泛的場景。在Glide拜隧、EventBus3宿百、Butterknifer、Tinker洪添、ARouter等等常用框架中都有注解處理器的身影垦页。但是你可能會發(fā)現(xiàn),這些框架中對注解的定義并不是
SOURCE
級別薇组,更多的是CLASS
級別外臂,別忘了:CLASS
包含了SOURCE
坐儿,RUNTIME
包含SOURCE
律胀、CLASS
宋光。
CLASS
定義為 CLASS
的注解,會保留在class文件中炭菌,但是會被虛擬機(jī)忽略(即無法在運(yùn)行期反射獲取注解)罪佳。此時完全符合此種注解的應(yīng)用場景為字節(jié)碼操作。如:AspectJ黑低、熱修復(fù)Roubust中應(yīng)用此場景赘艳。
所謂字節(jié)碼操作即為,直接修改字節(jié)碼Class文件以達(dá)到修改代碼執(zhí)行邏輯的目的克握。在程序中有多處需要進(jìn)行是否登錄的判斷蕾管。
如果我們使用普通的編程方式,需要在代碼中進(jìn)行 if-else
的判斷菩暗,也許存在十個判斷點掰曾,則需要在每個判斷點加入此項判斷。此時停团,我們可以借助AOP(面向切面)編程思想旷坦,將程序中所有功能點劃分為: 需要登錄
與 無需登錄
兩種類型,即兩個切面佑稠。對于切面的區(qū)分即可采用注解秒梅。
//Java源碼
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface Login {
}
@Login
public void jumpA(){
startActivity(new Intent(this,AActivity.class));
}
public void jumpB(){
startActivity(new Intent(this,BActivity.class));
}
在上訴代碼中, jumpA
方法需要具備登錄身份舌胶。而 Login
注解的定義被設(shè)置為 CLASS
捆蜀。因此我們能夠在該類所編譯的字節(jié)碼中獲得到方法注解 Login
。在操作字節(jié)碼時幔嫂,就能夠根據(jù)方法是否具備該注解來修改class中該方法的內(nèi)容加入 if-else
的代碼段:
//Class字節(jié)碼
@Login
public void jumpA() {
if (this.isLogin) {
this.startActivity(new Intent(this, LoginActivity.class));
} else {
this.startActivity(new Intent(this, AActivity.class));
}
}
public void jumpB() {
startActivity(new Intent(this,BActivity.class));
}
注解能夠設(shè)置類型元素(參數(shù))漱办,結(jié)合參數(shù)能實現(xiàn)更為豐富的場景,如:運(yùn)行期權(quán)限判定等婉烟。
RUNTIME
注解保留至運(yùn)行期娩井,意味著我們能夠在運(yùn)行期間結(jié)合反射技術(shù)獲取注解中的所有信息。
處理注解
一般新建一個庫似袁。例如叫:Compiler
洞辣,在app的gradle里添加依賴 annotationProcessor project(':Compiler')
新建一個類繼承 AbstractProcessor
來處理注解
要添加SupportedAnnotationTypes
注解,聲明自定義注解的全類名
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes("com.XXX.XXX.Bala")
public class BalaProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Messager messager = processingEnv.getMessager();
//NOTE是日志等級
messager.printMessage(Diagnostic.Kind.NOTE, "================================");
//xxxx
// http
//
return false;
}
}
注冊 BalaProcessor
昙衅。
在 Compiler
庫中的 src/main
目錄下新建 resources/META-INF.services/javax.annotation.processing.Processor
文件扬霜。一定要這個目錄和這個文件名。
在 Processor
文件中寫入 Processor
的全類名完成注冊
com.XXX.XXX.BalaProcessor
反射
一般情況下而涉,我們使用某個類時必定知道它是什么類著瓶,是用來做什么的,并且能夠獲得此類的引用啼县。于是我們直接對這個類進(jìn)行實例化材原,之后使用這個類對象進(jìn)行操作沸久。
反射則是一開始并不知道我要初始化的類對象是什么,自然也無法使用 new 關(guān)鍵字來創(chuàng)建對象了余蟹。這時候卷胯,我們使用 JDK 提供的反射 API 進(jìn)行反射調(diào)用。反射就是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意方法和屬性;并且能改變它的屬性威酒。是Java被視為動態(tài)語言的關(guān)鍵窑睁。
Java反射機(jī)制主要提供了以下功能:
- 在運(yùn)行時構(gòu)造任意一個類的對象
- 在運(yùn)行時獲取或者修改任意一個類所具有的成員變量和方法
- 在運(yùn)行時調(diào)用任意一個對象的方法(屬性)
Class
反射始于Class, Class是一個類葵孤,封裝了當(dāng)前對象所對應(yīng)的類的信息担钮。 一個類中有屬性,方法尤仍,構(gòu)造器等裳朋,比如說有一個Person類,一個Order類吓著,一個Book類鲤嫡,這些都是不同的類,現(xiàn)在需要一個類绑莺,用來描述類暖眼,這就是
Class,它應(yīng)該有類名纺裁,屬性诫肠,方法,構(gòu)造器等欺缘。Class是用來描述類的類栋豫。
Class類是一個對象照鏡子的結(jié)果,對象可以看到自己有哪些屬性谚殊,方法丧鸯,構(gòu)造器,實現(xiàn)了哪些接口等等嫩絮。對于每個類而言丛肢,JRE 都為其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個類的有關(guān)信息剿干。 對象只能由系統(tǒng)建立對象蜂怎,一個類(而不是一個對象)在 JVM 中只會有一個Class實例。
獲得 Class 對象
獲取Class對象的三種方式
- 通過類名獲取
類名.class
- 通過對象獲取
對象名.getClass()
- 通過全類名獲取
Class.forName(全類名)
classLoader.loadClass(全類名)
- 使用 Class 類的
forName
靜態(tài)方法
public static Class<?> forName(String className)
- 直接獲取某一個對象的 class
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;
- 調(diào)用某個對象的
getClass()
方法
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();
判斷是否為某個類的實例
一般地置尔,我們用 instanceof
關(guān)鍵字來判斷是否為某個類的實例杠步。同時我們也可以借助反射中 Class 對象的
isInstance()
方法來判斷是否為某個類的實例,它是一個 native 方法:
public native boolean isInstance(Object obj);
判斷是否為某個類的類型
public boolean isAssignableFrom(Class<?> cls)
創(chuàng)建實例
通過反射來生成對象主要有兩種方式。
- 使用Class對象的newInstance()方法來創(chuàng)建Class對象對應(yīng)類的實例幽歼。
Class<?> c = String.class;
Object str = c.newInstance();
- 先通過Class對象獲取指定的Constructor對象朵锣,再調(diào)用Constructor對象的newInstance()方法來創(chuàng)建實例。這種方法可以用指定的構(gòu)造器構(gòu)造類的實例试躏。
//獲取String所對應(yīng)的Class對象
Class<?> c = String.class;
//獲取String類帶一個String參數(shù)的構(gòu)造器
Constructor constructor = c.getConstructor(String.class);
//根據(jù)構(gòu)造器創(chuàng)建實例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
獲取構(gòu)造器信息
得到構(gòu)造器的方法
Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數(shù)類型的public構(gòu)造函數(shù)(包括父類)
Constructor[] getConstructors() -- 獲得類的所有公共構(gòu)造函數(shù)
Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數(shù)類型的構(gòu)造函數(shù)(包括私有)
Constructor[] getDeclaredConstructors() -- 獲得類的所有構(gòu)造函數(shù)(與接入級別無關(guān))
獲取類構(gòu)造器的用法與上述獲取方法的用法類似猪勇。主要是通過Class類的getConstructor方法得到Constructor類的一個實例设褐,而Constructor類有一個newInstance方法可以創(chuàng)建一個對象實例:
public T newInstance(Object ... initargs)
獲取類的成員變量(字段)信息
獲得字段信息的方法
Field getField(String name) -- 獲得命名的公共字段
Field[] getFields() -- 獲得類的所有公共字段
Field getDeclaredField(String name) -- 獲得類聲明的命名的字段
Field[] getDeclaredFields() -- 獲得類聲明的所有字段
調(diào)用方法
獲得方法信息的方法
Method getMethod(String name, Class[] params) -- 使用特定的參數(shù)類型颠蕴,獲得命名的公共方法
Method[] getMethods() -- 獲得類的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數(shù)類型,獲得類聲明的命名的方法
Method[] getDeclaredMethods() -- 獲得類聲明的所有方法
當(dāng)我們從類中獲取了一個方法后助析,我們就可以用 invoke() 方法來調(diào)用這個方法犀被。 invoke 方法的原型為:
public Object invoke(Object obj, Object... args)
利用反射創(chuàng)建數(shù)組
數(shù)組在Java里是比較特殊的一種類型,它可以賦值給一個Object Reference 其中的Array類為
java.lang.reflect.Array類外冀。我們通過Array.newInstance()創(chuàng)建數(shù)組對象寡键,它的原型是:
public static Object newInstance(Class<?> componentType, int length);
反射獲取泛型真實類型
當(dāng)我們對一個泛型類進(jìn)行反射時,需要得到泛型中的真實數(shù)據(jù)類型雪隧,來完成如json反序列化的操作西轩。此時需要通過 Type
體系來完成。 Type
接口包含了一個實現(xiàn)類(Class)和四個實現(xiàn)接口脑沿,他們分別是:
-
TypeVariable
- 泛型類型變量藕畔。可以泛型上下限等信息庄拇;
-
ParameterizedType
- 具體的泛型類型注服,可以獲得元數(shù)據(jù)中泛型簽名類型(泛型真實類型)
-
GenericArrayType
- 當(dāng)需要描述的類型是泛型類的數(shù)組時,比如List[],Map[]措近,此接口會作為Type的實現(xiàn)溶弟。
-
WildcardType
- 通配符泛型,獲得上下限信息瞭郑;
TypeVariable
public class TestType <K extends Comparable & Serializable, V> {
K key;
V value;
public static void main(String[] args) throws Exception {
// 獲取字段的類型
Field fk = TestType.class.getDeclaredField("key");
Field fv = TestType.class.getDeclaredField("value");
TypeVariable keyType = (TypeVariable)fk.getGenericType();
TypeVariable valueType = (TypeVariable)fv.getGenericType();
// getName 方法
System.out.println(keyType.getName()); // K
System.out.println(valueType.getName()); // V
// getGenericDeclaration 方法
System.out.println(keyType.getGenericDeclaration()); // class com.test.TestType
System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
// getBounds 方法
System.out.println("K 的上界:"); // 有兩個
for (Type type : keyType.getBounds()) { // interface java.lang.Comparable
System.out.println(type); // interface java.io.Serializable
}
System.out.println("V 的上界:"); // 沒明確聲明上界的, 默認(rèn)上界是 Object
for (Type type : valueType.getBounds()) { // class java.lang.Object
System.out.println(type);
}
}
}
ParameterizedType
public class TestType {
Map<String, String> map;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("map");
System.out.println(f.getGenericType()); // java.util.Map<java.lang.String,java.lang.String>
ParameterizedType pType = (ParameterizedType) f.getGenericType();
System.out.println(pType.getRawType()); // interface java.util.Map
for (Type type : pType.getActualTypeArguments()) {
System.out.println(type); // 打印兩遍: class java.lang.String
}
}
}
GenericArrayType
public class TestType<T> {
List<String>[] lists;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("lists");
GenericArrayType genericType = (GenericArrayType) f.getGenericType();
System.out.println(genericType.getGenericComponentType());
}
}
WildcardType
public class TestType {
private List<? extends Number> a; // 上限
private List<? super String> b; //下限
public static void main(String[] args) throws Exception {
Field fieldA = TestType.class.getDeclaredField("a");
Field fieldB = TestType.class.getDeclaredField("b");
// 先拿到泛型類型
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
// 再從泛型里拿到通配符類型
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法測試
System.out.println(wTypeA.getUpperBounds()[0]); // class java.lang.Number
System.out.println(wTypeB.getLowerBounds()[0]); // class java.lang.String
// 看看通配符類型到底是什么, 打印結(jié)果為: ? extends java.lang.Number
System.out.println(wTypeA);
}
}
Gson反序列化
static class Response<T> {
T data;
int code;
String message;
@Override
public String toString() {
return "Response{" +
"data=" + data +
", code=" + code +
", message='" + message + '\'' +
'}';
}
public Response(T data, int code, String message) {
this.data = data;
this.code = code;
this.message = message;
}
}
static class Data {
String result;
public Data(String result) {
this.result = result;
}
@Override
public String toString() {
return "Data{" +
"result=" + result +
'}';
}
}
static class ChildTypeRefrence{
Response<Data> t;
}
public static void main(String[] args) {
Response<Data> dataResponse = new Response(new Data("數(shù)據(jù)"), 1, "成功");
Gson gson = new Gson();
String json = gson.toJson(dataResponse);
System.out.println(json);
//為什么TypeToken要定義為抽象類辜御?
/**
* 有花括號: 代表是匿名內(nèi)部類,創(chuàng)建一個匿名內(nèi)部類的實例對象
* 沒花括號:創(chuàng)建實例對象
* 匿名內(nèi)部類是一個類屈张,是class我抠。對象只是一個對象,拿不到泛型的具體信息袜茧,因為泛型已經(jīng)被擦除了菜拓。但是類是有ChildTypeRefrence來保存泛型的簽名
*/
Response<Data> resp = gson.fromJson(json, new TypeToken<Response<Data>>() {
}.getType());
System.out.println(resp.data.result);
}
在進(jìn)行GSON反序列化時,存在泛型時笛厦,可以借助 TypeToken
獲取Type以完成泛型的反序列化纳鼎。但是為什么 TypeToken
要被定義為抽象類呢?
因為只有定義為抽象類或者接口,這樣在使用時贱鄙,需要創(chuàng)建對應(yīng)的實現(xiàn)類劝贸,此時確定泛型類型,編譯才能夠?qū)⒎盒蛃ignature信息記錄到Class元數(shù)據(jù)中逗宁。
應(yīng)用
模擬ButterKnife
- 添加注解
InjectView
import androidx.annotation.IdRes;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {
@IdRes int value();
}
- 設(shè)置注解
@InjectView(R.id.tv)
private TextView tv;
- 反射獲取注解并賦值
import android.app.Activity;
import android.view.View;
import java.lang.reflect.Field;
public class InjectUtils {
public static void injectView(Activity activity) {
Class<? extends Activity> cls = activity.getClass();
//獲得此類所有的成員
Field[] declaredFields = cls.getDeclaredFields();
for (Field filed : declaredFields) {
// 判斷屬性是否被InjectView注解聲明
if (filed.isAnnotationPresent(InjectView.class)){
InjectView injectView = filed.getAnnotation(InjectView.class);
//獲得了注解中設(shè)置的id
int id = injectView.value();
View view = activity.findViewById(id);
//反射設(shè)置 屬性的值
filed.setAccessible(true); //設(shè)置訪問權(quán)限映九,允許操作private的屬性
try {
//反射賦值
filed.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
- 實際設(shè)置值
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.tv)
private TextView tv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectUtils.injectView(this);
tv.setText("XXXXXX");
}
}