Java reflect 反射學習筆記
阿新 • • 發佈:2019-02-06
clas parameter 告訴 關鍵字 對象 報錯 getclass exc ==
- class 類的使用
- 萬事萬物皆對象 (基本數據類型, 靜態成員不是面向對象), 所以我們創建的每一個類都是對象, 即類本身是java.lang.Class類的實例對象, 但是這些對象不需要 new 出來, 因為java.lang.Class類的構造方法是私有的;
- 任何一個類都是Class類的實例對象.這個實例對象有三種表達方式: (我們新建一個Student類)
Class c1 = Student.class; // 實際告訴我們任何一個類都有一個隱含的靜態成員變量class(知道類名時用) Student stu = new Student(); Class c2 = stu.getClass(); // 已知該類的對象通過getClass方法(知道對象時用) try { Class c3 = Class.forName("com.cnblogs.reflect.Student");// 會有一個ClassNotFoundException異常 } catch (ClassNotFoundException e) { e.printStackTrace(); }
ps: 官網解釋說, c1, c2表示 Student類的類類型(class type), 類也是對象, 是Class類的實例對象, 這個對象我們稱之為該類的類類型
這裏有一點值得註意的是: 當我們執行System.out.println(c1 == c2)
時, 結果是true
, 這是為什麽? 原因是不管c1, c2都代表了Student類的類類型, 一個類可能是Class類的一個實例對象.
我們完全可以通過類的類類型創建該類的對象實例, 即通過c1或者c2創建Student的實例;
Student stu = (Student) c1.newInstance(); // 前提是Student裏必須要有無參構造方法, 否則會報異常
- 動態加載類
- 編譯時加載類是靜態加載類
new 創建對象是靜態加載類, 在編譯時刻就需要加載所有可能使用到的類, 如果有一個缺失, 那麽整個文件都無法通過編譯; - 運行時加載類是動態加載類
Class c = Class.forName(“類全名”)
, 不僅表示了類的類型, 還表示了動態加載類, 編譯不會報錯, 在運行時才會加載, 使用接口標準能更方便胴體加載類的實現. 功能性的類盡量使用動態加載, 而不用靜態加載.
- 獲取方法信息
- 基本的數據類型,
void
關鍵字都存在類類型
Class c1 = int.class; // int的類類型 Class c2 = String.class; // String的類類型, 可以理解為編譯生成生成的那個String.class字節碼文件 Class c3 = double.class; Class c4 = Double.class; Class c5 = void.class;
- Class類的基本API操作
public static void printClassMessage(Object obj) {
Class c = obj.getClass();
// 獲取類的類名稱;
System.out.println("類的名稱是: " + c.getName());
System.out.println("---------------------------------");
Method[] methods = c.getMethods();
for (Method method : methods) {
// 得到方法返回值類型的類類型
Class returnType = method.getReturnType();
System.out.println("returnType = " + returnType.getName());
// 得到方法的名稱
System.out.println("method = " + method.getName());
// 獲取參數類型 -> 得到的是參數列表的類類型
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class parameterClass : parameterTypes) {
System.out.println("parameterClass = " + parameterClass.getName());
}
System.out.println("---------------------------------");
}
}
- 獲取成員變量構造函數信息
public static void printFieldMessgae(Object obj) {
Class<?> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 得到成員變量的類型的類類型
Class<?> fieldType = field.getType();
String typeName = fieldType.getName();
System.out.println("typeName = " + typeName);
// 得到成員變量的名稱
String fieldName = field.getName();
System.out.println("fieldName = " + fieldName);
}
/**
* 獲取構造函數
*/
Constructor<?>[] constructors = c.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("constructor = " + constructor.getName());
/**
* 獲取構造函數的參數的類類型
*/
Class<?>[] parameterTypes = constructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("parameterType = " + parameterType.getName());
}
}
}
- 方法反射的基本操作
- 如何獲取某個方法
方法的名稱和方法的參數列表才能決定某個方法
Method m = c.getDeclaredMethod("方法名", 可變參數列表(參數類型.class))
- 方法的反射操作
m.invoke(對象, 參數列表)
方法如果沒有返回值, 返回null, 如果有返回值, 返回Object,
然後再強轉為原函數的返回值類型;
- 通過反射了解集合泛型的本質
ArrayList list1 = new ArrayList();
ArrayList<String> list2 = new ArrayList();
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.println(c1 == c2); // -> true
Ps: 因為反射的操作都是編譯之後的操作, 也就是運行時的操作, c1 == c2
返回true
, 說明編譯之後集合的泛型是去泛型化的.
那麽我們可以理解為, Java集合中的泛型, 是用於泛指錯誤類型元素輸入的, 比如在list2中我們add一個int,
Java reflect 反射學習筆記