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反射机制就已经不能动态修改它的值了. ...
随机推荐
- fail to start File System Check
fail to start File System Check 方法A: 输入root的密码 cd /etc 1 vim /etc/fstab 将所有分区最后的数字 1和2 全都改为0 reboot ...
- sed -i 's/Search_String/Replacement_String/g' Input_File sed详细手册
本文列出的十五个例子可以帮助你掌握 sed 命令.如果要使用 sed 命令删除文件中的行,去下面的文章.注意:由于这是一篇演示文章,我们使用不带 -i 选项的 sed 命令,该选项会在 Linux 终 ...
- 攻防世界(八)web2
攻防世界系列:web2 1.代码审计 知识补充: strrev(string):反转字符串 strlen(string):字符串长度 substr(string,start,length):截取字符 ...
- shell基础之函数
shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数.给这段代码起个名字称为函数名,后续可以直接调用该段代码. 格式: func() { #指定函数名 command # ...
- ELK学习实验016:filebeat收集tomcat日志
filebeat收集tomcat日志 1 安装tomcat [root@node4 ~]# yum -y install tomcat tomcat-webapps tomcat-admin-weba ...
- LTP--linux稳定性测试 linux性能测试 ltp压力测试 内核更新 稳定性测试
LTP--linux稳定性测试 linux性能测试 ltp压力测试 zhangzj1030关注14人评论33721人阅读2011-12-09 12:07:45 说明:在写这篇文章之前,本人也不曾了 ...
- ExpressionHelp2
public static class ExpressionHelp { private static Expression<T> Combine<T>(this Expres ...
- java面试一日一题:java中的垃圾回收器
问题:请讲下java中垃圾回收器有哪些? 分析:该问题主要考察hotspot虚拟机下实现的垃圾回收器 回答要点: 主要从以下几点去考虑, 1.垃圾回收器的种类 2.每种垃圾回收器的着重点是什么 前边的 ...
- 『动善时』JMeter基础 — 34、JMeter接口关联【XPath提取器】
目录 1.XPath提取器介绍 2.XPath提取器界面详解 3.XPath提取器的使用 (1)测试计划内包含的元件 (2)网易首页请求界面内容 (3)XPath提取器界面内容 (4)百度首页请求界面 ...
- jupyter notebook 默认文件路径修改以及启动
其实这个方法有时候不是特别有效额 方法一: 查了网上好多其他的方法,但是都没用,只好独辟蹊径了. 首先找到anaconda的安装路径,找到jupyter notebook,我的是如下: 发送快捷方式到 ...