《深入理解 Java 虛擬機器》閱讀筆記2系列:方法呼叫
阿新 • • 發佈:2021-01-17
Java反射總結
Class 類的使用
類是物件,類是java.lang.Class類的例項物件 Class Foo{}; 三種表示方式: //第一種表達方式:任何一個類都有一個隱含的靜態成員變數class Class c1=Foo.class;//類名.class //第二種表達方式:已知該類的物件通過getClass方法 Class c2=foo.getClass();//物件.getClass //c1、c2表示了Foo類的類型別(class type) //第三中表達方式 Class c3=null; try{ c3=Class.forName("所在包.Foo");//類的全稱 } catch(ClassNotFoundException e){ e.printStackTrace(); } //通過類的類型別建立該類的物件例項,c1是Foo類的類型別,創建出Foo類的物件 Foo foo=(Foo)c1.newInstance();//需要無參構造方法
Java動態載入類
Class.forName("類的全稱");
1. 不僅表示了類的類型別,還代表了動態載入類
2. 區分編譯執行
3. 編譯時刻載入類是靜態載入類、執行時刻載入類是動態載入類
4. new建立物件是靜態載入類,在編譯時刻就需要載入所有可能用到的類
5. 功能性類使用動態載入
Java獲取資訊的方法
//關鍵字都存在類型別,.class方法
1. 方法的反射
2. 成員變數的反射
3. 建構函式的反射
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect. Field;
import java.lang.reflect.Method;
public class ClassUtil {
//列印類的資訊,包括類的成員函式、成員變數(只獲取成員函式)
//@param obj 該物件所屬類的資訊
public static void printMehtodClassMessage(Object object) {
Class c = object.getClass();
//c是子類的類型別
String name = c.getName();
System.out.println (name);
//Method類,方法物件
//一個成員方法就是一個Method物件
//getMethods()方法獲取的是所有的public的函式,包括父類繼承而來的
Method[] methods = c.getMethods();
//getDeclaredMethods()獲取的是所有該類自己宣告的方法,不問訪問許可權
Method[] declaredMethods = c.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
//得到方法的返回值型別的類型別
Class returnType = methods[i].getReturnType();
System.out.print(returnType.getName() + ' ');
//得到方法的名稱
System.out.print(methods[i].getName() + '(');
//獲取引數型別,得到引數列表的型別的類型別
Class[] paramTypes = methods[i].getParameterTypes();
for (Class paramType : paramTypes) {
System.out.print(paramType.getName() + ",");
}
System.out.println(')');
printFieldMessage(c);
}
}
//獲取成員變數的資訊
public static void printFieldMessage(Object object) {
Class c = object.getClass();
//成員變數也是物件
//java.lang.reflect.Field
//Field類封裝了關於成員變數的操作
//getFields()方法獲取的是所有的public的成員變數的資訊
Field[] fields = c.getFields();
//getDeclaredFields()獲取的是該類自己宣告的成員變數的資訊
Field[] declaredFields = c.getDeclaredFields();
for (Field field : declaredFields) {
//得到成員變數的成員的類型別
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成員變數的名稱
String fieldName=field.getName();
System.out.println(typeName+" "+fieldName );
}
}
//列印物件的建構函式的資訊
public static void printConMessage(Object object){
Class c = object.getClass();
//建構函式也是物件
//java.lang.Constructor中封裝了建構函式的資訊
//getConstructors()獲取所有的public的建構函式
Constructor[] constructors = c.getConstructors();
//getDeclaredConstructors()得到所有得得建構函式
Constructor[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.print(declaredConstructor.getName()+"(");
//獲取建構函式的引數列表:得到的是引數列表的類型別
Class[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class parameterType : parameterTypes) {
String name = parameterType.getName();
System.out.print(name+",");
}
System.out.println(")");
}
}
}
方法的反射
1. 如何獲取某個方法
方法的名稱和方法的引數列表參能唯一決定某個方法
2. 方法的反射操作
method.invoke(物件,引數列表)
3. 為什麼要用方法的反射
why?指定方法名稱呼叫方法
舉個實際應用的案例:通過標準JavaBean的屬性名獲取其屬性值BeanUtil類
4. 通過Class,Method來認識泛型的本質
package reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class MethodDemo4 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
ArrayList<String> strings = new ArrayList<>();
Class c1 = arrayList.getClass();
Class c2 = strings.getClass();
System.out.println(c1==c2);//為真
//反射的操作都是編譯後的操作
//c1==c2結果返回true說明編譯之後集合的泛型是去泛型化的
//Java中集合的泛型,是防止錯誤輸入的,只在編譯階段有效,繞過編譯就無效了
//驗證;通過方法的反射操作來繞過編譯
try {
Method c1Method = c1.getMethod("add",Object.class);
Method c2Method = c2.getMethod("add", Object.class);/*此時可以新增其他型別*/
// Method c2Method = c2.getMethod("add", String.class);此為正確
try {
c2Method.invoke(strings,3);
System.out.println("陣列長度為="+strings.size());//結果為
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
for (Object string : strings) {
System.out.println("陣列內容為="+string);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}