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

存在这样一个类:

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反射机制开发经验总结的更多相关文章

  1. 第28章 java反射机制

    java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...

  2. Java反射机制

    Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射:     静态编译:在编译时确定类型,绑定对象,即通过 ...

  3. java基础知识(十一)java反射机制(上)

    java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...

  4. java基础知识(十一)java反射机制(下)

    1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...

  5. Java反射机制专题

    ·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...

  6. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  7. Java反射机制DOME

    Java反射机制 public class TestHibernate { @Test public void TestHb(){ try { Class cs = Class.forName(&qu ...

  8. 反射——Java反射机制

    反射概述 什么是反射? ①   反射的概念是由Smith在1982年首次提出的,主要指程序可以访问.检测和修改它本身状态或行为的一种能力. ②   JAVA反射机制是在运行状态中,对应任意一个类,都能 ...

  9. Java反射机制可以动态修改实例中final修饰的成员变量吗?

    问题:Java反射机制可以动态修改实例中final修饰的成员变量吗? 回答是分两种情况的. 1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了. ...

随机推荐

  1. [刷题] PTA 03-树2 List Leaves

    程序: 1 #include <stdio.h> 2 #include <queue> 3 #define MaxTree 20 4 #define Null -1 5 usi ...

  2. Linux_搭建Samba服务(认证访问)

    [RHEL8]-SMBserver:[RHEL7]-SMBclient !!!测试环境我们首关闭防火墙和selinux(SMBserver和SMBclient都需要) [root@localhost ...

  3. shell基础之for循环语句

    For语句 格式:for name [ [ in [ word ... ] ] ; ] do list ; done for 变量名 in 取值列表; do 命令 done 或者 for 变量名 in ...

  4. 常用Python第三方库简介

    如果说强大的标准库奠定了Python发展的基石,丰富的第三方库则是python不断发展的保证,随着python的发展一些稳定的第三库被加入到了标准库里面,这里有6000多个第三方库的介绍 下表中加粗并 ...

  5. Spring 是什么?

    概述 Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好.易于测试.可重用的代码. Spring 框架是一个开源的 Ja ...

  6. APP测试(appium+Python基础操作)一

    一.Appium入门案例 demo from appium import webdriver from time import sleep # server 启用参数 desired_caps = { ...

  7. System Verilog设计例化和连接

  8. curl测试代理连接某个域名的连接时间

    缘由:需要查询一下某些代理访问指定域名所消耗的时间,来判断是否是代理连接受限 以下代理均为示例代理,无法真正连接 1. 通过curl方式来测试指定代理的连接情况,代理无账号密码 curl -x 127 ...

  9. 支持边云协同终身学习特性,KubeEdge子项目Sedna 0.3.0版本发布!

    摘要:随着边缘设备数量指数级增长以及设备性能的提升,边云协同机器学习应运而生,以期打通机器学习的最后一公里. 本文分享自华为云社区<支持边云协同终身学习特性,KubeEdge子项目Sedna 0 ...

  10. ALD技术,相机去噪,图像传感器

    ALD技术,相机去噪,图像传感器 1. 作为镜片的防反射涂层技术被关注的ALD(atomic layer deposition)的引入趋势. (a)为什么需要一种新的防止反射的涂层技术? ALD被认为 ...