Java开发反射机制的实战经验总结

网友投稿 225 2022-12-29

Java开发反射机制的实战经验总结

目录前言一、创建Class的三种方式二、反射获取类的所有属性和属性类型三、反射动态修改类属性的注解值四、反射获取类的方法及调用方式总结

前言

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

存在这样一个类:

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) {

thttp://his.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获取存储到的,便是这http://个注解里所有的属性与对应的属性值。

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

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

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())

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

}

总结

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:网站翻译接口api(网站翻译怎么用)
下一篇:免费的api新闻数据接口(数据api接口网站)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~