反射相关练习

反射相关练习

演示的实体类如下

package com.mongodb.model;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Date;

/**
 * 汽车类
 * @author: gl_stars
 * @data: 2020年 09月 09日 17:39
 **/
@Data
@Document(collection = "user")
public class CarDO {

    @Id
    @Indexed
    private Long id ;

    /**
     * 小汽车名称
     */
    private String name ;

    /**
     * 厂家
     */
    private String manufactor ;

    /**
     * 生产日期
     */
    private Date dateOfManufacture ;
}

一、反射获取对象信息

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName(HouseDO.class.getName());

// 这种方式也OK
// ClassLoader loader = Thread.currentThread().getContextClassLoader();
// Class clazz = loader.loadClass(HouseDO.class.getName());

    System.out.println("===============本类属性===============");
// 取得本类的全部属性
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        // 权限修饰符
        int mo = field.getModifiers();
        // 访问修饰符
        String priv = Modifier.toString(mo);

        // 属性类型 输出格式为 class java.lang.Long
        Class<?> type = field.getType();
        // 数据类型 输出格式为:java.lang.Long
        String typeName = type.getName();

        // 属性名称
        String fieldName = field.getName();
    }
    System.out.println("==========实现的接口或者父类的属性==========");
// 取得实现的接口或者父类的属性,上面的使用只是方法不同而已。getFields();
    Field[] filedFather = clazz.getFields();
    for (Field field : filedFather) {
        // 权限修饰符
        int mo = field.getModifiers();
        // 访问修饰符
        String priv = Modifier.toString(mo);

        // 属性类型 输出格式为 class java.lang.Long
        Class<?> type = field.getType();
        // 数据类型 输出格式为:java.lang.Long
        String typeName = type.getName();

        // 属性名称
        String fieldName = field.getName();
    }
}

二、反射给对象赋值

  • 方式一
public static void main(String[] args) throws Exception {
    try {
        // 通过类装载器获取CarDO类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz = loader.loadClass(CarDO.class.getName());

        // 获取类的默认构造器对象并通过它实例化CarDO
        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
        CarDO car = (CarDO) cons.newInstance();
        car.setDateOfManufacture(new Date());
        car.setId(14656L);
        car.setName("比亚迪");
        car.setManufactor("比亚迪厂家");
        System.out.println(car);
        // 输出结果:CarDO(id=14656, name=比亚迪, manufactor=比亚迪厂家, dateOfManufacture=Thu Mar 11 01:20:21 CST 2021)
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 方式二
public static void main(String[] args) throws Exception {
    try {
        // 通过类装载器获取CarDO类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz = loader.loadClass(CarDO.class.getName());

      // 获取类的默认构造器对象并通过它实例化CarDO
        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
        CarDO car = (CarDO) cons.newInstance();

        // 通过反射方法设置属性
        Method setBrand = clazz.getMethod("setId", Long.class);
        setBrand.invoke(car, 14645646546l);
        Method setColor = clazz.getMethod("setName", String.class);
        setColor.invoke(car, "长安");
        Method setMaxSpeed = clazz.getMethod("setManufactor", String.class);
        setMaxSpeed.invoke(car, "我家生产的");
        System.out.println(car);
        // 输出结果为 :CarDO(id=14645646546, name=长安, manufactor=我家生产的, dateOfManufacture=null)
    } catch (Exception e) {
        e.printStackTrace();
    }
}

三、适用案例(Map集合转为实体对象)

使用MongoDB朋友都明白,如果我们使用连集合查询的时候需要使用聚合。但是聚合查询有个特点,我们实体类里面的 id字段会保存在MongoDB中会做 _id。但是如果使用聚合查询时,返回给我们的字段依然是 _id而不是 id。但是返回来的是一个Map集合,从表我们可以根据自己定义的kay直接从Map集合中获取做一个强转是没有问题的。但是主表有多少个字段就在MongoDB返回的这个Map集合中就有多少个key。总不能让我们一个字段一个字段的去取出来存入对象吧,所以使用反射写一个工具类,直接调用即可将Map集合转为实体对象。

package com.centre.common.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 将Map集合转为对象
 * <p>
 *     使用范例:
 *     public static void main(String[] args) throws Exception {
 *         Map<String,Object> map = new HashMap<>();
 *         map.put("id",12346546l);
 *         map.put("name","比亚迪,长安");
 *         map.put("manufactor","比亚迪厂家,长安厂家");
 *         map.put("dateOfManufacture",new Date());
 *
 *         HandleMapToObject<CarDO> toObject = new HandleMapToObject<CarDO>();
 *         CarDO carDO = toObject.mapToObject(map, CarDO.class,true);
 *         System.out.println(carDO);
 *         // 输出结果:CarDO(id=12346546, name=比亚迪,长安, manufactor=比亚迪厂家,长安厂家, dateOfManufacture=Thu Mar 11 00:41:32 CST 2021)
 *     }
 * </p>
 * @Author: Stars
 * @Date: 2021/3/10 22:06
 */
public class HandleMapToObject<T> {

    /**
     * 将Map集合转为实体对象
     * @param map Map集合
     * @param t 转换后的对象
     * @param considerThread true:考虑现成安全,false:不考虑
     * @return
     * @throws Exception
     */
    private T mapToObject(Map map, Class<T> t,Boolean considerThread) throws Exception {
        Class<?> clazz = null;
        if (considerThread) {
            //通过类装载器获取t类对象
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            clazz = loader.loadClass(Class.forName(t.getName()).getName());
        } else {
            clazz = Class.forName(Class.forName(t.getName()).getName());
        }
        //获取类的默认构造器对象并通过它实例化t
        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
        T t1 = (T) cons.newInstance();
        // 获取t对象的所有属性
        Field[] fields = clazz.getDeclaredFields();
        // 将t对象中属性保存为Map的key值,数据类型保存为value值
        Map<String, Object> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, Field::getType));
        // 取出map集合中的全部数据
        Class<?> finalClazz = clazz;
        map.forEach((k, v) -> {
            try {
                // 给当前属性赋值,本来数据类型应该fieldMap.get(k).getClass()这样写。但是上面获取t对象的数据类型时Field::getType这种方法应用不能再获取getName()属性,所以这里是class java.lang.String的类型了,不能再点getClass()了。     所有强转了一下。(Class) fieldMap.get(k)
                Method setBrand = finalClazz.getMethod(initcap(String.valueOf(k)), (Class) fieldMap.get(k));
                setBrand.invoke(t1, v);
            } catch (Exception e) {
                System.out.println("map集合转数组异常:"+t.getClass());
            }
        });
        return t1;
    }

    /***
     * 将对象属性转为set方法名
     * @param str 转大写的字符串
     * @return
     */
    public static String initcap(String str) {
        return "set" + str.substring(0, 1).toUpperCase() + str.substring(1) ;
    }
}

  • 实现思路

Map集合名为为map和实体对象类型传入。创建一个Map集合保存对象的属性和数类型,Map集合名为fieldMap,因为反射赋值时需要使用对象属性和属性类型。将对象的属性保存为fieldMap集合的key,数据类型保存为fieldMap集合的value。然后循环map集合,因为MongoDB返回来的这个map集合的key就是对象的属性名。所以循环map集合,取出key值到fieldMap集合中获取数类型。现在属性名、数据类型和保存的数据都知道了,接下来的事情就是水到渠成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值