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