目录
  • 一、创建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) {
        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反射机制的文章就介绍到这了,更多相关java开发反射机制内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!