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<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反射机制开发经验总结的更多相关文章
- 第28章 java反射机制
java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...
- Java反射机制
Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射: 静态编译:在编译时确定类型,绑定对象,即通过 ...
- java基础知识(十一)java反射机制(上)
java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...
- java基础知识(十一)java反射机制(下)
1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...
- Java反射机制专题
·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...
- java反射机制深入详解
java反射机制深入详解 转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...
- Java反射机制DOME
Java反射机制 public class TestHibernate { @Test public void TestHb(){ try { Class cs = Class.forName(&qu ...
- 反射——Java反射机制
反射概述 什么是反射? ① 反射的概念是由Smith在1982年首次提出的,主要指程序可以访问.检测和修改它本身状态或行为的一种能力. ② JAVA反射机制是在运行状态中,对应任意一个类,都能 ...
- Java反射机制可以动态修改实例中final修饰的成员变量吗?
问题:Java反射机制可以动态修改实例中final修饰的成员变量吗? 回答是分两种情况的. 1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了. ...
随机推荐
- /var/log/syslog日志usb接口
p:~# cat /proc/bus/input/devices |grep usbP: Phys=usb-0000:00:05.1-1/buttonS: Sysfs=/devices/pci0000 ...
- im-chooser重新选择输入法框架在终端执行im-chooser命令
CentOS 7安装图像桌面.Ibus拼音输入法一.图形桌面安装1.安装额外包yum源(extra package for Enterprise Linux) yum install epel-rel ...
- Linux进阶之补充知识篇
一.Linux系统的主要特点: 开放性:指系统遵循世界标准规范,特别是遵循开放系统互连(OSI)国际标准 多用户:允许多个用户从相同或不同终端上同时使用同一台计算机 多任务:它是指计算机同时执行多个程 ...
- Linux进阶之bond链路聚合
一.简述: 一般来讲,生产环境必须提供7×24小时的网络传输服务.借助于网卡绑定技术,不仅可以提高网络传输速度,更重要的是,还可以确保在其中一块网卡出现故障时,依然可以正常提供网络服务.假设我们对两块 ...
- [Django高级之Auth模块]
[Django高级之Auth模块] auth模块 ←详情点击查看 1.Auth模块是什么 Auth模块是Django自带的用户认证模块: 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统 ...
- C# Asp.Net 实现PPT/PDF转成图片(不依赖office)
最近公司有个需求,将PPT课件转成图片列表,然后在前端展示成轮播图,于是一开始通过Microsoft.Office.Interop.PowerPoint包实现了这个需求具体代码如下: /// < ...
- Nginx 配置实例-配置虚拟主机
Nginx 配置实例-配置虚拟主机 配置基于域名的虚拟主机 1. 配置域名为 aaa.domain.com 的虚拟主机 1.1 nginx 中虚拟主机的配置 1.2 相关目录及文件的创建 1.3 验证 ...
- Jmeter- 笔记10 - 在GUI生成html报告
步骤1.在聚合报告,浏览一个存放jtl文件的路径,输入不存在的jtl文件,确定后会出现如下图弹窗,不用理会,关掉 步骤2.运行脚本 步骤3.打开工具 -> Generate HTML repor ...
- TheSuperego 实验五 团队作业2:毕业设计选题系统
项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST 这个作业要求链接 https://www.cnblogs.com/nwnu-dai ...
- Megengine量化
Megengine量化 量化指的是将浮点数模型(一般是32位浮点数)的权重或激活值用位数更少的数值类型(比如8位整数.16位浮点数)来近似表示的过程. 量化后的模型会占用更小的存储空间,还能够利用许多 ...