热门IT资讯网

Java开发反射机制实例代码分析

发表于:2024-11-23 作者:热门IT资讯网编辑
编辑最后更新 2024年11月23日,本文小编为大家详细介绍"Java开发反射机制实例代码分析",内容详细,步骤清晰,细节处理妥当,希望这篇"Java开发反射机制实例代码分析"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习

本文小编为大家详细介绍"Java开发反射机制实例代码分析",内容详细,步骤清晰,细节处理妥当,希望这篇"Java开发反射机制实例代码分析"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

前言

存在这样一个类:

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 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 values = (Map) memberValues.get(invocationHandler);        System.out.println(values);    }}

debug打断点,可以看到--

这个Map存储的是该@注解里的所有属性值,这里,@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获取存储到的,便是这个注解里所有的属性与对应的属性值。

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

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

InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");memberValues.setAccessible(true);Map values = (Map) 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 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开发反射机制实例代码分析"文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注行业资讯频道。

0