我是靠谱客的博主 欣喜皮皮虾,最近开发中收集的这篇文章主要介绍码神总结的Java反射机制经验,太精辟了!,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

原创不易,有用就关注一下。要是帮到了你 就给个三连吧,多谢支持。


### >>三期资源-3T免费视频资料。
 

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

存在这样一个类:

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;
  }

关注公众号【程序员漫话编程】,后台回复 ”学习资料“ ,即可获得3T免费视频资源。

原创不易,有用就关注一下。要是帮到了你 就给个三连吧,多谢支持。
 

觉得不错的小伙伴,记得帮我 点个赞和关注哟,笔芯笔芯~**

作者:码工
 

有问题请留言或者私信,可以 微信搜索:程序员漫话编程,关注公众号获得更多免费学习资料。

最后

以上就是欣喜皮皮虾为你收集整理的码神总结的Java反射机制经验,太精辟了!的全部内容,希望文章能够帮你解决码神总结的Java反射机制经验,太精辟了!所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部