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实例中)
    }
}

 

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