Java反射机制详解

一、反射机制的概念
指在运行状态中,能够动态获取任意一个类或者对象信息的功能叫Java语言的反射机制。

二、反射机制的作用
反射机制能让我们更加灵活的创建代码,使得代码可以在运行时装配。反射机制提供以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理

三、反射机制的图解

这里写图片描述

上图是Java的内存模型,下面将举例说明Java运行代码的流程。假如写了一段代码:Object o=new Object();首先运行代码,然后JVM会启动并将代码编译成一个.class文件,然后被类加载器加载进JVM的内存中,你的类Object将加载到方法区中,创建了Object类的Class对象将加载到堆中(Class对象是一个特殊的对象,是用来创建其它对象的对象,每个类仅有唯一的Class对象)。JVM创建对象前,会先检查类是否加载,并寻找类对应的Class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。到此,Object o=new Object()这行代码就运行完毕,然后JVM关闭退出了。
那么反射跟这有什么关系呢,由于上面的程序对象是自己new的,程序相当于写死了给JVM去跑。而反射是什么呢?当我们的程序在运行时,需要动态的加载一些类,这些类可能之前用不到所以不用加载到JVM,这时候就可以看到反射的好处了。

四、反射机制的使用

1、获取Class对象

获取Class对象有三种方法:

  • Class.forName(“类名字符串”) (注意:类名字符串必须是全称,包名+类名)

  • 类字面常量法:类名.class

  • 实例对象.getClass()

2、判断是否为某个类的实例

一般地,我们用instanceof关键字来判断是否为某个类的实例

    object instanceof Integer

3、创建实例

通过反射来生成对象主要有两种方式:

  • 使用Class对象的newInstance()方法来创建Class对象对应类的实例
    Class<?> click = String.class;
    Object obj = click.newInstance();
  • 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
    //获取String所对应的Class对象
    Class<?> click = String.class;
    //获取String类带一个String参数的构造器
    Constructor constructor = click.getConstructor(String.class);
    //根据构造器创建实例
    Object obj = constructor.newInstance("123456");

4、获取方法

获取某个Class对象的方法集合,主要有以下几个方法:

  • getDeclaredMethods()方法:返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
    public Method[] getDeclaredMethods() throws SecurityException
  • getMethods()方法:返回某个类的所有公用(public)方法,包括其继承类的公用方法。
    public Method[] getMethods() throws SecurityException
  • getMethod方法:返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
    public Method getMethod(String name, Class<?>... parameterTypes)

5、获取构造器信息

获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例。

6、获取类的成员变量(字段)信息

主要是这几个方法,在此不再赘述:

  • getFiled: 访问公有的成员变量
  • getDeclaredField:所有已声明的成员变量。但不能得到其父类的成员变量

7、调用方法

当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为:

    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

五、反射机制的实例

public static void main(String args[]){
    String[] attrs = {"province", "city", "mediaId", "groupId",   "campaignId", "creativeId"};
    // 将attrs转化为list
    List<String> keyList = Arrays.asList(attrs);
    Class<?> clicksClass = ImpressionClick.class;//获取创建ImpressionClick类的class对象
    ImpressionClick clicks = (ImpressionClick) clicksClass.newInstance();//创建实例
    Method method = null;//获取某个特定的方法
    // 封装特征数据
            Method method = null;//获取某个特定的方法
            for (String key : keySet) {
                if (keyList.contains(key)) {
                    String methodStr = "set" + key.toUpperCase().substring(0, 1) + key.substring(1);
                    Object value = dataJson.get(key);//获取value值
                    if(value instanceof Integer) {//如果value是Integer型
                        method = clicksClass.getMethod(methodStr, int.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Integer) value); // 自动装箱,//调用clicks对象的method方法,传递"(Integer) value"作为参数,方法的执行结果是retValue
                    }else if(value instanceof Double) {//如果value是Double型
                        method = clicksClass.getMethod(methodStr, double.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Double) value); // 自动装箱
                    }else if(value instanceof Long) {//如果value是Long型
                        method = clicksClass.getMethod(methodStr, long.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Long) value); // 自动装箱
                    }else if(value instanceof String) {//如果value是String型
                        method = clicksClass.getMethod(methodStr, String.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (String) value); // 自动装箱
                    }else if(value instanceof Float) {//如果value是Float型
                        method = clicksClass.getMethod(methodStr, Float.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Float) value); // 自动装箱
                    }else if(value instanceof Boolean) {//如果value是Boolean型
                        method = clicksClass.getMethod(methodStr, Boolean.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Boolean) value); // 自动装箱
                    }else if(value instanceof Date) {//如果value是Date型
                        method = clicksClass.getMethod(methodStr, Date.class); // 此时获得了set方法
                        Object retValue = method.invoke(clicks, (Date) value); // 自动装箱
                    }
                }
            }
            }
**
 * 展示点击数据
 */
public class ImpressionClick {

    private Long timestamp;       //时间戳(竞价时间UTC毫秒数) Long
    private String platformUserId;//用户在平台的ID String
    private String impId;         //展示Id String
    private String ua;            //User-agent String
    private String ip;            //IP地址 String
    private String country;       //国家编码 String
    private String province;      //省编码 String
    private String city;          //市编码 String
    private String mediaId;       //App的ID String
    private String pageUrl;       //当前页的url String
    private int groupId;          //组Id Int
    private int campaignId;       //活动ID Int
    private int creativeId;       //创意Id Int(素材id)

    //省略属性的get set方法

由此可见,这段代码如果写成遍历每个属性的set的话,不仅大大增加了代码量,而且代码写的很死,不灵活。但是反射机制也有它的缺点,就是会增加计算复杂度,所以要慎用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值