Java注解和反射,你學(xué)會(huì)了嗎?
注解
注解(Annotation)是JDK5引入的一種代碼輔助工具,其核心作用是對(duì)類、方法、變量、參數(shù)和包進(jìn)行標(biāo)注,通過反射來訪問這些標(biāo)注信息,以此在運(yùn)行時(shí)改變所注解對(duì)象的行為,Java中的注解由內(nèi)置注解和元注解組成。
注解與注釋
- Java注解又稱之為Java標(biāo)注,是JDK5開始支持加入源代碼的特殊語法元數(shù)據(jù)
- 普通的注釋在編譯后的class文件中是不存在的,而注解附加的信息則根據(jù)需要可以保存到class文件中,甚至運(yùn)行期加載的class對(duì)象中
元注解介紹
創(chuàng)建注解
public @interface [AnnotationName]{}
元注解(描述注解的一種方式)
1.@Retention 定義注解的生命周期(source、class、runtime)
2.@Documented 文檔注解,會(huì)被javadoc工具文檔化
3.@Inherited 是否讓子類繼承該注解
4.@Target 描述注解的應(yīng)用范圍,可選內(nèi)容如下所示:
- TYPE:可以用來修飾類、接口、注解類型或枚舉類型
- PACKAGE:可以用來修飾包
- PARAMETER:可以用來修飾參數(shù)
- ANNOTATION_TYPE:可以用來修飾注解類型
- METHOD:可以用來修飾屬性
- FIELD:可以用來修飾屬性(包括枚舉常量)
- CONSTRUCTOR:可以用來修飾構(gòu)造器
- LOCAL_VARIABLE:可以用來修飾局部變量
創(chuàng)建使用注解示例
注解的創(chuàng)建方式:
- 配置元注解,由元注解來聲明當(dāng)前注解的作為范圍和聲明周期。
- 注解中如果需要添加信息,可以用以上方式添加。
- 注解信息支持java的基本數(shù)據(jù)結(jié)構(gòu)。
1.創(chuàng)建注解 @Study
@Target({ElementType.FIELD, ElementType.TYPE}) // 元注解,定義注解的修飾范圍,可以設(shè)置多個(gè)
@Retention(RetentionPolicy.RUNTIME) // 元注解,定義注解的聲明周期
public @interface Study { // 注解內(nèi)容可以設(shè)置值,也可以不設(shè)置值
// 其中的屬性是支持JAVA的八大屬性的 byte、short、int、long、float、double、boolean、char
// 如果屬性為value,那么使用時(shí),賦值可以不寫 "value ="
String name() default "Neco Deng"; // 表示定義了一個(gè)name屬性,并且設(shè)置了默認(rèn)值為Neco Deng
String[] mores(); // 表示定義了一個(gè)名字為mores的字符串?dāng)?shù)組屬性,并且沒有默認(rèn)值,即該屬性需要顯示定義
}
2.使用注解
@Study(mores = {"first", "second"}) // 在類上使用注解,這里必須定義mores, 不然會(huì)報(bào)錯(cuò)
public class Person {
private int id;
@Study(mores = {"first", "second"}) // 在屬性上使用注解,這里必須定義mores, 不然會(huì)報(bào)錯(cuò)
private String name;
}
反射
反射(Reflection):在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為Java語言的反射。
反射的優(yōu)缺點(diǎn)
- 通過反射可以使程序代碼訪問裝載到JVM中的類的內(nèi)部信息,獲取已裝載類的屬性信息,獲取已裝載類的方法,獲取已裝載類的構(gòu)造方法信息。
- 反射提供了JAVA程序的靈活性和擴(kuò)展性,降低耦合性,提高自適應(yīng)能力。
- 反射會(huì)對(duì)性能造成一定的影響,同時(shí)讓代碼的可讀性變低。
常用的反射API
方法名 | 返回值 | 參數(shù)描述 |
Class.forName() | 獲取類的元信息 | 當(dāng)前類文件的具體位置 |
clazz.getClass() | 獲取類的元信息 | 無 |
clazz.getDeclaredFields() | 獲取當(dāng)前類中的所有屬性 | 當(dāng)前類文件的具體位置 |
setAccessible(true) | 設(shè)置當(dāng)前屬性為可見 | true或false |
getMethods() | 獲取類所有方法 | 無 |
invoke(obj) | 通過反射執(zhí)行方法 | 類的元信息 |
getAnnotation(class) | 獲取注解 | 需要獲取到額注解的Class |
例子
public class ReflectionDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException,
InstantiationException, NoSuchMethodException, InvocationTargetException {
// 實(shí)例1:通過反射獲取到Class元信息
Person person = new Person();
Class<? extends Person> aClass1 = person.getClass(); // 通過getClass獲取元信息
Class<?> aClass2 = Class.forName("com.model.Person"); // 通過forName獲取元信息
// 實(shí)例2:通過反射獲取類名,包名
String name = aClass1.getName(); // 全路徑類名 > cn.lazyfennec.model.Person
String simpleName = aClass1.getSimpleName(); // 不包含路徑 > Person
Package aPackage = aClass1.getPackage(); // 包名 > package cn.lazyfennec.model
System.out.println(name);
System.out.println(simpleName);
System.out.println(aPackage);
System.out.println("===============================");
// 實(shí)例3:獲取類屬性
Field[] declaredFields = aClass1.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 實(shí)例4:獲取類屬性的具體的值
person.setId(1);
person.setName("Neco");
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true); // 設(shè)置屬性可見可訪問,處理私有屬性無法訪問的問題
System.out.println(declaredField.get(person));
}
// 實(shí)例4的另一種寫法,只是簡(jiǎn)單的寫法,可以進(jìn)行優(yōu)化
Object obj = aClass1.newInstance(); // 實(shí)例化一個(gè)新的對(duì)象, 相當(dāng)于反射中的實(shí)例化
declaredFields = obj.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
if (declaredField.getName().equals("name")) {
declaredField.set(obj, "Neco");
} else {
declaredField.set(obj, 1);
}
System.out.println(declaredField.get(obj));
}
// 實(shí)例5:反射獲取當(dāng)前類的方法
Method[] methods = aClass1.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
Method method = aClass1.getMethod("getString");
Object invoke = method.invoke(obj);
System.out.println(invoke);
// 實(shí)例6:反射獲得注解
Study study = aClass1.getAnnotation(Study.class); // 從類中獲取注解
System.out.println(study);
String[] mores = study.mores();
String name1 = study.name();
System.out.println("name: " + name1 + " mores: " + mores);
// 從方法上獲取注解
methods = aClass1.getDeclaredMethods();
for (Method method1 : methods) {
Study annotation = method1.getAnnotation(Study.class);
if (annotation == null) continue;
String name2 = annotation.name();
String[] mores1 = annotation.mores();
System.out.println("name: " + name2 + " mores: " + mores1);
}
// 從屬性上獲取注解
declaredFields = aClass1.getDeclaredFields();
for (Field declaredField : declaredFields) {
Study annotation = declaredField.getAnnotation(Study.class);
if (annotation == null) continue;
String annotationName = annotation.name();
String[] annotationMores = annotation.mores();
System.out.println("name: " + annotationName + " mores: " + annotationMores);
}
}
}
參考
https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/index.html