浅谈

Java 反射 Reflection

2019-03-07  本文已影响0人  都是浮云啊

[TOC]

开篇

Java 中的反射对于经常写业务的程序员来说几乎是很少很少见的,但是当去研究那些流行框架和自己尝试编写底层框架的时候,反射发挥着很重要的作用。那么什么是反射呢,在定义中就是:在Java 运行时可以访问、检测和修改它本身状态或行为的一种能力,它允许运行中的Java程序获取自身的信息,并且可以操作类或者对象的内部的属性。与之密切相关的就是 Class类了,之前在 类加载器的文章中有提到,JVM会为每个类管理一个 Class 对象,这个对象包含了与类有关的信息,Class 和 java.lang.reflect 搭配为Java反射的实现提供了基础。主要的类及关系图如下,其中最重要的三个类分别是 Field Method Constructor 分别描述一个类的属性、方法、构造器,它们都直接或者间接继承 AccessibleObject 类,这个父类提供了访问控制检查的功能。

Java反射架构

通过Class获取类的信息

package cn.xisole.sky.reflect;

import lombok.Data;

/**
 * OrderDO 订单实体类
 *
 * @author yupao
 * @since 2019/3/7 下午11:03
 */
@Data
public class OrderDO {
    /**
     * 订单id
     */
    private String orderId;
    /**
     * 会员id
     */
    private String customerId;
    /**
     * 会员id
     */
    private String shopId;
    /**
     * 订单的创建时间
     */
    private Long createTime;

    public OrderDO(String orderId, String customerId, String shopId, Long createTime) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.shopId = shopId;
        this.createTime = createTime;
    }

    public OrderDO() {
    }
}
// 子类

package cn.xisole.sky.reflect;

import lombok.Data;

/**
 * TakeoutOrderDO 外卖订单实体类
 *
 * @author yupao
 * @since 2019/3/7 下午11:06
 */
@Data
public class TakeoutOrderDO extends OrderDO{
    /**
     * 配送地址
     */
    private String deliveryAddress;
    /**
     * 客户电话
     */
    private String customerPhone;
    /**
     * 客户姓名
     */
    private String customerName;
    public TakeoutOrderDO(String orderId, String customerId, String shopId, Long createTime) {
        super(orderId, customerId, shopId, createTime);
    }

    /**
     * 定义一个方法
     */
    public void printInfo(){
        System.out.println(this);
    }

    public TakeoutOrderDO() {
        super();
    }

    @Override
    public String toString() {
        return "TakeoutOrderDO{" +
                "deliveryAddress='" + deliveryAddress + '\'' +
                ", customerPhone='" + customerPhone + '\'' +
                ", customerName='" + customerName + '\'' +
                '}' + super.toString();
    }
}

//测试类
package cn.xisole.sky.reflect;

import java.lang.reflect.*;

/**
 * MainReflect
 *
 * @author yupao
 * @since 2019/3/7 下午11:12
 */
public class MainReflect {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        /**
         * 一:获取 Class 对象的三种方式
         */
        /**
         * 通过 Class.forName 直接获取 Class 对象
         */
        Class c1 = Class.forName("cn.xisole.sky.reflect.TakeoutOrderDO");
        /**
         * 通过类直接获取 Class 对象
         */
        Class c2 = TakeoutOrderDO.class;

        /**
         * 通过实例的 getClass 方法获得 Class 对象
         */
        TakeoutOrderDO takeoutOrderDO = new TakeoutOrderDO("orderId","customerId","shopId",111L);
        Class c3 = takeoutOrderDO.getClass();

        System.out.println(c1 + "\n" + c2 + "\n" + c3);

        System.out.println("c1==c2==c3:"+(c1==c3 && c1==c3));
        /**
         * 二:通过反射来创建类的实例
         */
        /**
         * 1. 通过Class对象的 newInstance 方法来创建Class对象的实例
         */
        TakeoutOrderDO takeoutOrderDO1 = (TakeoutOrderDO)c1.newInstance();
        /**
         * 2. 通过Class对象获取指定的 Constructor对象,再调用Constructor对象的newInstance方法创建实例
         */
        Constructor constructor = c1.getConstructor(String.class,String.class,String.class,Long.class);
        TakeoutOrderDO takeoutOrderDO2 = (TakeoutOrderDO) constructor.newInstance("param1","param2","param3",111L);
        System.out.println(takeoutOrderDO1 + "\n" + takeoutOrderDO2);
        System.out.println("takeoutOrderDO1 == takeoutOrderDO2:"+(takeoutOrderDO1 == takeoutOrderDO2));

        /**
         * 三:通过反射获取类的信息
         */
        System.out.println("c1的父类:"+c1.getSuperclass().getName());
        System.out.println("c1的构造器:"+c1.getConstructor());
        System.out.println("c1的属性:");
        Field[] fields = c1.getDeclaredFields();
        for(Field field:fields){
            System.out.println(field.getType() +" "+ field.getName());
        }
        System.out.println("c1的方法:");
        Method[] methods = c1.getDeclaredMethods();
        for (Method method : methods){
            System.out.println(method.getName());
        }


    }

}

上面的Demo主要展示了如何获取Class类以及如果根据Class得到对象的实例。可以发现,当我们拿到了 Class 类的时候,我们就直接掌控了这个类了。无论是获取类的属性还是构造器还是方法,都只是Class对象的管理的一部分而已,因为在JVM内部,一个个的类就是一个个的Class。此外我们还可以对获取到的结果进行进一步的需要的操作,比如说可以得到Methon,然后Methon可以执行Invoke方法去执行等等诸如这种操作。

小结

反射的优点:

反射的缺点:
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成那么最好不用。在我们使用反射技术时,有一些缺点需要了解下:

上一篇下一篇

猜你喜欢

热点阅读