Blog 反射

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.spec.ECField;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Ans {
    public static void main(String[] args) throws Exception {
        test0();
        test1();
        test2();
        test3();
        test4();
    }

    static void test0() throws ClassNotFoundException {
        //Class類是final的,而且它的構造函數是private的,所以只有JVM可以構建Class
        //JVM是動態加載的,即使用到某個類時才加載,這也就是爲什麼把Log4j放入路徑後可以自動使用,否則會使用Commons Logging。因爲如果沒有Log4j存在於路徑中,就檢測不到這個類,也就不用加載

        Class cl = String.class,cl2 = ("").getClass();                  //這個是兩種常見的方式得到class
        Class cl3 = Class.forName("java.lang.String");                  //這是第三種
        System.out.println(cl==cl2);                                    //這裏是true,因爲每個類只有唯一的Class所以不管怎麼得到Class都是一個對象,所以相等
    }

    static void test1() {
        //在用反射得到Field或者Method時,不帶Declared是包含其父類的所有public成員,帶Declared是不包含父類的所有成員(這裏不只限於public)
        //雖然getField可以得到private的域,但是我們不能對其進行訪問,否則會出現IllegalAccessException,只有使用setAccessible
        //使用setAccessible時可能因爲JVM運行時存在的SecurityManager而出錯,有時SecurityManager會阻止對java,javax中域的setAccessible操作
        System.out.println(Ans.class.getModifiers());               //這個getModifiers是對類型的一種編碼,用一個int的不同位來表示其屬性(public,private,static,final...),詳情可見:https://blog.csdn.net/qq_39385118/article/details/83757536
    }

    static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //對於方法的使用與test1中對域的使用基本相同
        //有一點,當使用父類的class調用子類的重寫函數時,依然遵守多態原則,調用的是子類的函數
        class A {void a() {System.out.println("a");}}
        class B extends A {void a() {System.out.println("b");}}

        Method m = A.class.getDeclaredMethod("a");
        m.invoke(new B());
    }

    static void test3() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //java SE9之前Class.newInstance只能調用默認的public無參數構造方法,如果需要調用其他構造方法則需要Constructor.newInstance
        //但是在java SE9中刪除了Class.newInstance,而可以使用getConstructor和getDeclaredConstructor去構建對象,而對Declared的用法相似於getDeclaredMethod,具體用法如下
        class A {
            A() {System.out.println("unpublic");}
            A(int i) {System.out.println("int");}
        }

        class B {
            public B() {System.out.println("public");}
            public B(int i) {System.out.println("public int");}
        }

        A.class.getDeclaredConstructor().newInstance();
        //!A.class.getConstructor().newInstance();                                  這兩步中構造函數不是public,所以必須加Declared
        A.class.getDeclaredConstructor(int.class).newInstance(1);

        B.class.getConstructor().newInstance();
        B.class.getConstructor(int.class).newInstance(1);                   //而這裏可以
    }

    static void test4() {
        //可以使用getSuperClass獲得父類,除了Object父類爲null,其他都有父類(除了interface外(interface也是class))
        //查詢實現的接口應該調用getInterfaces
        //對任何沒有繼承接口的interface調用getSuperClass會返回null
        //getInterfaces不會返回父類實現的接口
        System.out.println(Object.class.getSuperclass());
        System.out.println(Integer.class.getSuperclass());
        System.out.println(Arrays.toString(ArrayList.class.getInterfaces()));
        System.out.println(Arrays.toString(List.class.getInterfaces()));

        //爲了判斷一個向上轉型是否成立可以使用isAssignableFrom
        System.out.println(Object.class.isAssignableFrom(Integer.class));
        System.out.println(Integer.class.isAssignableFrom(Object.class));
    }

    static void test5() {
        //對於動態代理,blog中講的比較淺,可以參考java編程思想裏面有非常詳細的解釋
        //Proxy.newProxyInstance中需要傳入一個classLoader,一個接口列表,一個InvocationHandler實例(代理的調用函數invoke就實現在這個InvocationHandler實例中)
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章