专栏首页二进制文集JDK源码分析 反射

JDK源码分析 反射

说明

对于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()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Google Protocol Buffers 数据交换协议

    protobuf(Protocol Buffers)是Google推出的一个结构化数据交换协议,用于传递自定义的消息格式,可用于同一台机器的进程间、不同设备进程...

    Yano_nankai
  • Java 代码模拟死锁

    Yano_nankai
  • Java 生产者消费者实现 —— BlockingQueue

    对着《Java 编程思想》,通过wait - notifyAll实现了生产者消费者模式。今天用BlockingQueue实现一下。

    Yano_nankai
  • 在C#中使用依赖注入-生命周期控制

    在使用依赖注入的过程当中,除了应用设计模式注意代码的变化隔离之外,另外一个重要的内容就是生命周期控制。

    newbe36524
  • 设计原则

    一、面向对象应用程序开发原则(SOLID) 1单一职责原则(SRP) 定义: 一个类应该只有一个发生变化的原因。这条原则曾被称为内聚性,即一个模块的组成元素之间...

    甜橙很酸
  • 学习Java基础知识,打通面试关七

    用户2196435
  • C# Command命令(行为型模式)+队列 实现事务,带异步命令重试机制和生命周期

    耦合是软件不能抵御变变化的根本性原因,不仅实体对象与实体对象之间有耦合关系(如创建性设计模式存在的原因),对象和行为之间也存在耦合关系.

    郑小超.
  • Entity Framework Core 实现全局查询过滤

    微软在 Entity Framework Core 2+ 中引入了全局查询过滤器,简化了构建多租户应用程序和实体软删除的复杂度。这篇文章我将通过代码的形式对全局...

    喵叔
  • JavaSE学习总结(四)——Java面向对象十分钟入门

    面向对象编程(Object Oriented Programming,OOP)是一种计算机模拟人类的自然思维方式的编程架构技术,解决了传统结构化开发方法中客观...

    张果
  • Java设计模式-抽象工厂模式

    抽象工厂模式,提供了一个创建一些列相关或相互依赖对象的接口,而无需指定它们具体的类

    桑鱼

扫码关注云+社区

领取腾讯云代金券