1. 程式人生 > 其它 >《深入理解 Java 虛擬機器》閱讀筆記2系列:方法呼叫

《深入理解 Java 虛擬機器》閱讀筆記2系列:方法呼叫

技術標籤:java反射class

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();
        }
    }
}