美文网首页Android知识
JDK源码分析 反射

JDK源码分析 反射

作者: 被称为L的男人 | 来源:发表于2017-08-07 08:51 被阅读298次

    说明

    对于JDK源码分析的文章,仅仅记录我认为重要的地方。源码的细节实在太多,不可能面面俱到地写清每个逻辑。所以我的JDK源码分析,着重在JDK的体系架构层面,具体源码可以参考:http://www.cnblogs.com/skywang12345/category/455711.html

    反射简介

    在运行状态中,我们可以根据“类的部分已知的信息”来还原“类的全部的信息”。

    类的部分已知的信息:

    • 类名
    • 类的对象

    类的全部信息

    • 属性
    • 方法
    • 继承关系
    • Annotation注解

    根据类名构造类

    代码示例

    User类

    public class User implements Serializable{
        private static final long serialVersionUID = 1510634274152200118L;
        
        private int id;
        private String passWord;
        
        public User() {
            System.out.println("Create user... ");
        }
        
        public User(int id, String passWord) {
            this.id = id;
            this.passWord = passWord;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getPassWord() {
            return passWord;
        }
        public void setPassWord(String passWord) {
            this.passWord = passWord;
        }
        @Override
        public String toString() {
            return "User [id=" + id + ", passWord=" + passWord + "]";
        }
    }
    

    根据类名,构造类的代码:

    @Test
    public void testReflection() throws Exception {
        Class<?> clazz = Class.forName("test.User");
        User user = (User) clazz.newInstance();
        System.out.println("user = " + user);
    }
    

    输出:

    Create user... 
    user = User [id=0, passWord=null]
    

    获取 class 对象

    @Test
    public void testClazz() throws Exception {
        Class<?> clazz1 = Class.forName("test.User");
        Class clazz2 = User.class;
        Class clazz3 = new User().getClass();
        System.out.println("clazz1: " + clazz1);
        System.out.println("clazz2: " + clazz2);
        System.out.println("clazz3: " + clazz3);
    }
    

    输出:

    Create user... 
    clazz1: class test.User
    clazz2: class test.User
    clazz3: class test.User
    

    class 的 API

    • 构造函数
    • 成员方法
    • 成员变量
    • 类的其它信息(如注解、包名、类名、继承关系等等)

    构造函数

    // 获取“参数是parameterTypes”的public的构造函数
    public Constructor    getConstructor(Class[] parameterTypes)
    // 获取全部的public的构造函数
    public Constructor[]    getConstructors()
    // 获取“参数是parameterTypes”的,并且是类自身声明的构造函数,包含public、protected和private方法。
    public Constructor    getDeclaredConstructor(Class[] parameterTypes)
    // 获取类自身声明的全部的构造函数,包含public、protected和private方法。
    public Constructor[]    getDeclaredConstructors()
    // 如果这个类是“其它类的构造函数中的内部类”,调用getEnclosingConstructor()就是这个类所在的构造函数;若不存在,返回null。
    public Constructor    getEnclosingConstructor()
    

    测试:

    @Test
    public void testConstructor() throws Exception {
        Class<?> clazz = Class.forName("test.User");
        Constructor<?> constructor = clazz.getDeclaredConstructor(null);
        Object object1 = constructor.newInstance();
        System.out.println(object1);
        
        Constructor<?> constructor2 = clazz.getDeclaredConstructor(new Class[] {int.class, String.class});
        Object object2 = constructor2.newInstance(1, "123456");
        System.out.println(object2);
    }
    

    输出:

    Create user... 
    User [id=0, passWord=null]
    User [id=1, passWord=123456]
    

    可以调用默认的构造函数,也可以通过

    clazz.getDeclaredConstructor(new Class[] {int.class, String.class})
    

    来调用User的含参构造函数

    public User(int id, String passWord) {
        this.id = id;
        this.passWord = passWord;
    }
    

    成员方法

    // 获取“名称是name,参数是parameterTypes”的public的函数(包括从基类继承的、从接口实现的所有public函数)
    public Method    getMethod(String name, Class[] parameterTypes)
    // 获取全部的public的函数(包括从基类继承的、从接口实现的所有public函数)
    public Method[]    getMethods()
    // 获取“名称是name,参数是parameterTypes”,并且是类自身声明的函数,包含public、protected和private方法。
    public Method    getDeclaredMethod(String name, Class[] parameterTypes)
    // 获取全部的类自身声明的函数,包含public、protected和private方法。
    public Method[]    getDeclaredMethods()
    // 如果这个类是“其它类中某个方法的内部类”,调用getEnclosingMethod()就是这个类所在的方法;若不存在,返回null。
    public Method    getEnclosingMethod()
    

    可以判断类中是否含有某个方法,也可以调用类中的任何一个方法(包括私有方法)。

    @Test
    public void testMethod() throws Exception {
        Class<?> clazz = Class.forName("test.User");
        
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }
        System.out.println();
        
        Method printInfo = clazz.getDeclaredMethod("printInfo", new Class[]{});
        User user = (User) clazz.newInstance();
        printInfo.invoke(user, null);
    }
    

    输出:

    Create user... 
    public java.lang.String test.User.toString()
    public int test.User.getId()
    public void test.User.printInfo()
    public void test.User.setId(int)
    public void test.User.setPassWord(java.lang.String)
    public java.lang.String test.User.getPassWord()
    User [id=0, passWord=null]
    

    成员变量

    // 获取“名称是name”的public的成员变量(包括从基类继承的、从接口实现的所有public成员变量)
    public Field    getField(String name)
    // 获取全部的public成员变量(包括从基类继承的、从接口实现的所有public成员变量)
    public Field[]    getFields()
    // 获取“名称是name”,并且是类自身声明的成员变量,包含public、protected和private成员变量。
    public Field    getDeclaredField(String name)
    // 获取全部的类自身声明的成员变量,包含public、protected和private成员变量。
    public Field[]    getDeclaredFields()
    
    @Test
    public void testField() throws Exception {
        Class<?> clazz = Class.forName("test.User");
        
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        
        // 创建并通过反射,修改一个 private 变量 id
        User user = (User) clazz.newInstance();
        Field field = clazz.getDeclaredField("id");
        field.setAccessible(true);
        field.set(user, 123);
        user.printInfo();
    }
    

    输出:

    private static final long test.User.serialVersionUID
    private int test.User.id
    private java.lang.String test.User.passWord
    Create user... 
    User [id=123, passWord=null]
    

    我们可以看到,User中对于id的定义:

    private int id;
    

    而在测试用例中,可以获取对象中私有的id变量,并直接修改内容,最终输出的id=123。

    类的其它信息

    注解

    // 获取类的"annotationClass"类型的注解 (包括从基类继承的、从接口实现的所有public成员变量)
    public Annotation<A>    getAnnotation(Class annotationClass)
    // 获取类的全部注解 (包括从基类继承的、从接口实现的所有public成员变量)
    public Annotation[]    getAnnotations()
    // 获取类自身声明的全部注解 (包含public、protected和private成员变量)
    public Annotation[]    getDeclaredAnnotations()
    

    “父类”和“接口”相关的API

    // 获取实现的全部接口
    public Type[]    getGenericInterfaces()
    // 获取父类
    public Type    getGenericSuperclass()
    

    相关文章

      网友评论

        本文标题:JDK源码分析 反射

        本文链接:https://www.haomeiwen.com/subject/jtjolxtx.html