Java开发反射机制的实战经验总结

目录
  • 前言
  • 一、创建Class的三种方式
  • 二、反射获取类的所有属性和属性类型
  • 三、反射动态修改类属性的注解值
  • 四、反射获取类的方法及调用方式
  • 总结

前言

我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用。

存在这样一个类:

package com.example.demo;
import com.alibaba.fastjson.annotation.JSONField;
public class User {
    private String name;
    @Value( value ="age_a")
    private String age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

一、创建Class的三种方式

1 - Class clazz = Class.forName("com.example.demo.User");

注意一点,这里的forName("xxx")的类名需要全名,且为接口或类,否则加载不了。

2 - User user = new User();

Class clazz2 = user.getClass();

3 - Class clazz3 = User.class;

以上三种方式,都可以获取到类User的Class对象,通过Class,即可以开始玩反射了。

二、反射获取类的所有属性和属性类型

Class clazz = User.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("属性名:"+field.getName());
    System.out.println("属性的类型:"+field.getGenericType().getTypeName());
}

打印输出User的属性和属性类型——

属性名:name

属性的类型:java.lang.String

属性名:age

属性的类型:java.lang.String

利用反射获取到类的字段属性后,是不是可以利用反射来创建一个对象呢?答案是肯定的。

例如,可以类似下面代码,通过反射得到的字段属性,进而创建一个对象。

Map<String,Object> fileds = new HashMap<>();
fileds.put("name","张三");
fileds.put("age","10");
Object o = User.class.newInstance();
 Field[] fields = o.getClass().getDeclaredFields();
 for (Field field : fields) {
     //设置后可用反射访问访问私有变量
     field.setAccessible(true);
     //通过反射给属性赋值
     field.set(o,fileds.get(field.getName()));
 }
 User user1 = (User) o;
 System.out.println(user1.toString());

什么场景下可能需要这样做的呢?像一些内部数据与外部数据字段的映射,就可以通过类似的字段反射方式,将源数据映射给目标数据,进而得到可以插入数据库的目标对象。

三、反射动态修改类属性的注解值

注意一点,我们在设置User类时,对其中一个字段加了注解:@Value( value ="age_a")。这是一种设置值的注解,既然是设置值,是否还可以在代码运行过程中,根据不同情况来动态修改呢?

字段上的注解,其实都存放在一个memberValues属性里,这是一个map,可以这样来获取——

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    //设置后可用反射访问访问私有变量
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
       //获取 annotation 这个代理实例所持有的 InvocationHandler
       InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
       // 获取 InvocationHandler 的 memberValues 字段
        Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
        memberValues.setAccessible(true);
        Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
        System.out.println(values);
    }
}

debug打断点,可以看到——

这个Map<String,Object>存储的是该@注解里的所有属性值,这里,@Value只有一个value属性——

public @interface Value {
    String value();
}

若把它换成类似@JSONField(name="age_a"),把上边的代码稍微修改下,如:

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
          InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(JSONField.class));
  ......
    }
}

@JSONField注解的内部属性有如下方式——

再运行刚刚的代码,可以看到,这里Map<String,Object>获取存储到的,便是这个注解里所有的属性与对应的属性值。

到了这一步,回到先前上边的问题,若要动态改变这个注解的值,怎么处理呢?

其实,很简单,只需要直接进行值设置就可以了,例如——

InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
values.put("value","new_age");
memberValues.setAccessible(false);

只是,注意一点是,这里的key需要对应上注解里是属性值。

四、反射获取类的方法及调用方式

 Object o=User.class.newInstance();
//通过反射获取到User的setAge方法,后面的String.class表示这个setAge方法的参数类型,若有多个,则按顺序列出
//同时,若为其他类型,如List,Long,则为List.class,Long.class
 Method m =  (Method) o.getClass().getMethod("setAge",String.class);
 m.invoke(o,"name");
 User user = (User) o;
 System.out.println(user);

打印可见,age已为name,说明setAge调用成功了。

这类使用场景,在代理当中出现比较多。

最后,通过反射实现一个Map转成对象的封装工具——

   public Object MapToObject(Object object,Map<String, Object> map) throws IllegalAccessException {
        Class cla =  object.getClass();
        Field[] fields = cla.getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            if("serialVersionUID".equals(field.getName()))continue;
            if(map.get(field.getName())!=null) {
                Object value=map.get(field.getName());
                value=convertValType(value,field.getType());
                field.set(object, value);
            }
        }
        return object;
    }

    private static Object convertValType(Object value, Class<?> fieldTypeClass) {
        Object o = null;
        if (Long.class.getName().equals(fieldTypeClass.getName())
                || long.class.getName().equals(fieldTypeClass.getName())) {
            o = Long.parseLong(value.toString());
        } else if (Integer.class.getName().equals(fieldTypeClass.getName())
                || int.class.getName().equals(fieldTypeClass.getName())) {
            o = Integer.parseInt(value.toString());
        } else if (Float.class.getName().equals(fieldTypeClass.getName())
                || float.class.getName().equals(fieldTypeClass.getName())) {
            o = Float.parseFloat(value.toString());
        } else if (Double.class.getName().equals(fieldTypeClass.getName())
                || double.class.getName().equals(fieldTypeClass.getName())) {
            o = Double.parseDouble(value.toString());
        } else {
            retVal = o;
        }
        return retVal;
    }

总结

到此这篇关于Java反射机制的文章就介绍到这了,更多相关Java开发反射机制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java的反射机制---动态调用对象的简单方法

    唉!我还真是在面试中学习新东东啊,一个公司刚刚给了个测试,不过我很奇怪的是为什么web developer的职位居然考java的反射机制题,不过学习研究一下反射机制对我来说是件好事啦! 先说说什么是java反射机制吧,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这 种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.主要功能:在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对 象:在运行时判断任意一个

  • 通过java反射机制动态调用某方法的总结(推荐)

    如下: public Object invokeMethod(String className, String methodName, Object[] args) throws Exception{ Class ownerClass = Class.forName(className); Object owner = ownerClass.newInstance(); Class[] argsClass = new Class[args.length]; for (int i = 0, j =

  • Java反射机制详解

    本文较为详细的分析了Java反射机制.分享给大家供大家参考,具体如下: 一.预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中.这些信息主要包括: 1.这个类型的全

  • 利用java反射机制调用类的私有方法(推荐)

    试想一下,如果你可以轻易地调用一个类的私有方法,那么是不是说你的封装都失效了?最近在看java的反射机制,发现居然可以利用java的反射机制去调用其他类的私有方法,至于这能干什么,那就见人见智了.. 我写的一段简易实例代码如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author thomaslwq * @version 创建时间:Sep 4, 201

  • Java反射机制的实现详解

    很多主流框架都使用了反射技术.像ssh框架都采用两种技术 xml做配置文件+反射技术. 与反射有关的类包. java.lang.reflect.*;和java.lang.Class; Java中所有类型(包括基本类型)都对应一个Class对象,这个Class就是java.lang.Class.即每一个类型,在Class中都有一个Class对象跟它对应.Class 没有公共构造方法.注意不是没有,是没有公共的. 如何获得Class对象 复制代码 代码如下: .针对每一个对象.getCalss(),

  • JAVA反射机制实例教程

    本文以实例形式详细讲述了Java的反射机制,是Java程序设计中重要的技巧.分享给大家供大家参考.具体分析如下: 首先,Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性.例如,使用它能获得 Java 类中各成员的名称并显示出来. Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性.例如,Pascal.C 或者 C++ 中就没有办法在程序中获得函数

  • Java反射机制的学习总结

    一.什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制 有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义.听了反射机制这节课后,才知道,原来这

  • 老生常谈Java反射机制(必看篇)

    什么是反射机制 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作.例如它允许一个java的类获取他所有的成员变量和方法并且显示出来.这个能特定我们不常看到,但是在其他的比如C或者C++语言中很不就存在这个特性.一个常见的例子是在JavaBean中,一些组件可以通过一个构造器来操作.这个构造器就是用的反射在动态加载的时候来获取的java中类的属性的. 主要的类 Class 类的实例表示正在运行的 Java 应用程序中的类和接口.Class没

  • java反射机制示例详解

    1.什么是反射?一个类有多个组成部分,例如:成员变量,方法,构造方法等.反射就是加载类,并解剖出类的各个组成部分. 2.加载类java中有一个Class类用于代表某一个类的字节码.Class类既然代表某个类的字节码,那就要提供加载某个类字节码的方法:forName().   此方法用于加载某个类的字节码到内存中,并使用class对象进行封装.另外2种得到class对象的方式:类名.class对象.getClass() 先创建一个简单的Person类 复制代码 代码如下: public class

  • java 利用java反射机制动态加载类的简单实现

    如下所示: ////////////////// Load.java package org.bromon.reflect; import java.util.ArrayList; import java.util.List; public class Load implements Operator { @Override public List<?> act(List<?> params) { // TODO Auto-generated method stub List<

随机推荐