反射及動態代理

反射(Reflect)

反射就是在運行時才知道要操作的類是什麼,並且可以在運行時獲取類的完整構造,並調用對應的方法。
是Java被視爲動態語言的關鍵,反射機制允許程序在執行期藉助於Reflection API取得任何類的內部信息,並能直接操作任意對象的內部屬性及方法。

  1. 在運行時構造任意一個類的對象。
  2. 運行時獲取任意一個類所具有的成員變量和方法。
  3. 在運行時調用任意一個對象的方法(屬性)。
    Java 是一門面向對象的語言。在面向對象的世界裏,萬事萬物皆對象,既然萬事萬物皆對象。我們寫的每一個類都可以看成一個對象,是 java.lang.Class 類的對象。當我們寫完一個類的Java文件,編譯成class文件的時候,編譯器都會將這個類的對應的class對象放在class文件的末尾。保存了類的元數據信息,一個類的元數據信息包括屬性,方法,構造器,實現了哪些接口等等,這些信息在Java裏都有對應的類來表示。

Class類

Class是一個類,封裝了當前對象所對應的類的信息。
Class類是一個對象照鏡子的結果,對象可以看到自己有哪些屬性,方法,構造器,實現了哪些接口等等。
對於每個類而言,JRE 都爲其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個類的有關信息。對象只能由系統建立對象,一個類(而不是一個對象)在 JVM 中只會有一個Class實例。
獲取Class對象的三種方式

  1. 通過類名獲取 類名.class
  2. 通過對象獲取 對象名.getClass()
  3. 通過全類名獲取 Class.forName(全類名)

Class類的常用方法

方法名 功能說明
static Class forNmae(String name) 返回指定類名的Class對象
Object newInstance() 調用缺省構造函數,返回該Class對象的一個實例
Object newInstantce(Object []args) 調用當前格式構造函數,返回Class對象的一個實例
getName() 返回Class對象鎖表示的實體(類,接口,數組類,基本類型或者void)名稱
Class getSuperClass() 返回當前Class對象的父類Class對象
Class [] getInterfases() 獲取當前Class對象的接口
ClassLoader getClassLoader() 返回該類的類加載器

類加載器、構造器、Method、Field

ClassLoader

public static void testClassLoader() throws ClassNotFoundException,
        FileNotFoundException {
    //1. 獲取一個系統的類加載器(可以獲取)
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    System.out.println(classLoader);


    //2. 獲取系統類加載器的父類加載器(擴展類加載器,可以獲取).
    classLoader = classLoader.getParent();
    System.out.println(classLoader);


    //3. 獲取擴展類加載器的父類加載器(引導類加載器,不可獲取).
    classLoader = classLoader.getParent();
    System.out.println(classLoader);


    //4. 測試當前類由哪個類加載器進行加載(系統類加載器):
    classLoader = Class.forName("xx.xx.xxxx")
            .getClassLoader();
    System.out.println(classLoader);


    //5. 測試 JDK 提供的 Object 類由哪個類加載器負責加載(引導類)
    classLoader = Class.forName("java.lang.Object")
            .getClassLoader();
    System.out.println(classLoader);
}

Constructor

 /*構造器相關*/
    public void testConstructor() throws Exception{
        String className = "xx.xx.xxxx.Person";
        Class<Person> clazz = (Class<Person>) Class.forName(className);

        System.out.println("獲取全部Constructor對象-----");
        Constructor<Person>[] constructors
                = (Constructor<Person>[]) clazz.getConstructors();
        for(Constructor<Person> constructor: constructors){
            System.out.println(constructor);
        }


        System.out.println("獲取某一個Constructor 對象,需要參數列表----");
        Constructor<Person> constructor
                = clazz.getConstructor(String.class, int.class);
        System.out.println(constructor);

        //2. 調用構造器的 newInstance() 方法創建對象
        System.out.println("調用構造器的 newInstance() 方法創建對象-----");
        Person obj = constructor.newInstance("Mark", 18);
        System.out.println(obj.getName());
    }

Field

/*域相關*/
    public void testField() throws Exception{
        String className = "xx.xx.xxxx.Person";
        Class clazz = Class.forName(className);

        System.out.println("獲取公用和私有的所有字段,但不能獲取父類字段");
        Field[] fields = clazz.getDeclaredFields();
        for(Field field: fields){
            System.out.print(" "+ field.getName());
        }
        System.out.println();
        System.out.println("---------------------------");


        System.out.println("獲取指定字段");
        Field field = clazz.getDeclaredField("name");
        System.out.println(field.getName());

        Person person = new Person("ABC",12);
        System.out.println("獲取指定字段的值");
        Object val = field.get(person);
        System.out.println(field.getName()+"="+val);

        System.out.println("設置指定對象指定字段的值");
        field.set(person,"DEF");
        System.out.println(field.getName()+"="+person.getName());

        System.out.println("字段是私有的,不管是讀值還是寫值," +
                "都必須先調用setAccessible(true)方法");
        field = clazz.getDeclaredField("age");
        field.setAccessible(true);
        System.out.println(field.get(person));
    }

Method

 /*方法相關*/
    public void testMethod() throws Exception{
        Class clazz = Class.forName("xx.xx.xxxx.Person");

        System.out.println("獲取clazz對應類中的所有方法," +
                "不能獲取private方法,且獲取從父類繼承來的所有方法");
        Method[] methods = clazz.getMethods();
        for(Method method:methods){
            System.out.print(" "+method.getName()+"()");
        }
        System.out.println("");
        System.out.println("---------------------------");

        System.out.println("獲取所有方法,包括私有方法," +
                "所有聲明的方法,都可以獲取到,且只獲取當前類的方法");
        methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            System.out.print(" "+method.getName()+"()");
        }
        System.out.println("");
        System.out.println("---------------------------");

        System.out.println("獲取指定的方法," +
                "需要參數名稱和參數列表,無參則不需要寫");
        //  方法public void setName(String name) {  }
        Method method = clazz.getDeclaredMethod("setName", String.class);
        System.out.println(method);
        System.out.println("---");

        //  方法public void setAge(int age) {  }
        /* 這樣寫是獲取不到的,如果方法的參數類型是int型
        如果方法用於反射,那麼要麼int類型寫成Integer: public void setAge(Integer age) {  }
        要麼獲取方法的參數寫成int.class*/
        method = clazz.getDeclaredMethod("setAge", int.class);
        System.out.println(method);
        System.out.println("---------------------------");


        System.out.println("執行方法,第一個參數表示執行哪個對象的方法" +
                ",剩下的參數是執行方法時需要傳入的參數");
        Object obje = clazz.newInstance();
        method.invoke(obje,18);

        /*私有方法的執行,必須在調用invoke之前加上一句method.setAccessible(true);*/
        method = clazz.getDeclaredMethod("privateMethod");
        System.out.println(method);
        System.out.println("---------------------------");
        System.out.println("執行私有方法");
        method.setAccessible(true);
        method.invoke(obje);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章