Spring boot项目反射学习笔记及突破泛型限制

Spring boot项目反射学习笔记

引用反射:
反射存在于java.lang.reflect包下,常用方法是Constructor、Field、Method。


认识Class,Class是反射的源头,可以获取对象做在类的信息,也可以通过class类的方法进行对象实例化操作,正常情况下,使用new关键字实例化对象,如果现在有已经实例化好的class对象,可以通过newInstance方法实例化对象。


反射的作用:

  • 动态创建对象
  • 动态操作属性
  • 动态执行方法

下面通过简单例子来理解反射:
首先创建简单的抽象类及对应的实现方法:

//抽象类
package com.dsr.dao;

import lombok.Data;

@Data
public abstract class Animal {
    public static String nickName;
    public int age;

    public abstract void eat();

}

//实现类
package com.dsr.dao;


import java.io.Serializable;

public class Dag extends Animal implements Serializable, Cloneable {
    private String type;
	//无参构造方法
    public Dag(){
        System.out.println("dog");
    }
    @Override
    public void eat() {
        System.out.println("dog  eat");
    }
    private void guard(){

    }

}


接下来简单理解为什么要使用反射:

package com.dsr.controller;

import com.dsr.dao.Dag;

import java.lang.reflect.InvocationTargetException;

public class TestReflection {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //通常我们调用对象及方法时:如果知道操作对象,不需要反射
        Dag dog = new Dag(); //创建对象
        dog.eat();
        dog.age = 13;   //操作属性

        //如果不知道操作的对象(运行的时候才知道对象),需要反射
        String className = "com.dsr.dao.Dag";
        //根据字符串创建对象
        Class clazz= Class.forName(className);
        //使用反射来创建对象
        clazz.getConstructor().newInstance();
       

    }
}

在这里插入图片描述
可以看到创建了两个对象。

什么是运行时才知道要操作的对象,就是要操作的对象存在于一个配置文件中,我们在运行时,才可以出发这个对象的情况。比如我创建一个配置文件:
在这里插入图片描述
将要操作的对象放在了配置文件中。


反射使用教程:

使用反射获取对象及对象结构信息

package com.dsr.clazz;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class TestClazz {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        //获取一个类的类对象:class信息
        Class clazz = Class.forName("com.dsr.dao.Dag");

        //从类对象中获取结构信息:get
        //基本信息  成员变量  方法  构造方法
        System.out.println(clazz.getName()); //完整路径
        System.out.println(Arrays.toString(clazz.getInterfaces()));//接口 将接口转换为字符串
        System.out.println(clazz.getSimpleName());//简单类名
        System.out.println(clazz.getSuperclass()); //父类
        System.out.println(clazz.getModifiers()); //获取修饰符
        System.out.println(Modifier.toString(clazz.getModifiers()));//将修饰符转换为字符串

        //Field[] field = clazz.getFields(); //获取包括上级类的所有公共属性
        Field[] field = clazz.getDeclaredFields();//获取所有属性 但是不包括上级
        for(Field f : field){
            System.out.println(f);
        }
        Field f1 = clazz.getField("nickName");
        System.out.println(f1);

        //Method[] methods = clazz.getMethods();//获取包括上级类的所有公共方法
        Method[] methods = clazz.getDeclaredMethods();//获取所有方法 但是不包括上级
        for(Method m :methods){
            System.out.println(m);
        }

        Constructor constructor = clazz.getConstructor();//获取无参构造方法
        System.out.println(constructor);
        Constructor[] constructors = clazz.getConstructors();//获取所有构造方法
        for(Constructor c :constructors){
            System.out.println(c);
        }
        Constructor c1 = clazz.getConstructor(String.class);//获取有参构造方法
        //System.out.println(c1);
    }
}

使用反射创建对象的三种方式

package com.dsr.clazz;

import com.dsr.dao.Dag;

import javax.xml.crypto.Data;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/*
* 第一种方法:Class clazz = Class.forName("com.dsr.dao.Dag");
* 第二种方法: Class clazz = Dag.class;
* 第三种方法:Dag dog = new Dag();
        Class clazz = dog.getClass();
当用方法二三时,已经知道要操作的对象。forname方法不能用来获取基本数据类型、数组
* */
public class TestClazz1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        //获取一个类的类对象:class信息
        //Class clazz = Class.forName("com.dsr.dao.Dag");

        //Class clazz = Dag.class;

        Dag dog = new Dag();
        Class clazz = dog.getClass();
        //从类对象中获取结构信息:get
        //基本信息
        System.out.println(clazz.getName()); //完整路径
        System.out.println(Arrays.toString(clazz.getInterfaces()));//接口
        System.out.println(clazz.getSimpleName());//简单类名
        System.out.println(clazz.getSuperclass()); //父类
        System.out.println(Modifier.toString(clazz.getModifiers()));


    }
}

使用反射获取无参构造方法

package com.dsr.clazz;

import com.dsr.dao.Dag;

import java.lang.reflect.Constructor;

//使用反射调用无参构造方法创建对象
public class TestContrutor {
    public static void main(String[] args) throws NoSuchMethodException {
        //不使用
        Dag dog = new Dag();
        
        //使用
        String className = "com.dsr.dao.Dag";
        Class clazz = className.getClass();
        Constructor constructor = clazz.getConstructor();
        System.out.println(constructor);

    }
}

使用反射获取属性与其类似。

使用反射获取泛型信息、及突破泛型限制

package com.dsr.clazz;

import com.dsr.dao.Admin;
import com.dsr.dao.Animal;
import com.dsr.dao.Dag;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class TestGeneric {
    public void method(Map<Animal, Dag> map, List<Admin> list){
    }

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clazz = TestGeneric.class;
        Method m1 = clazz.getMethod("method",Map.class,List.class);
        //获取不带泛型的参数
        Type[] type = m1.getParameterTypes();
        System.out.println(type.length);
        for(int i = 0 ;i < type.length ;i++){
            System.out.println(type[i]);
        }
        //获取带泛型的参数
        Type[] types = m1.getGenericParameterTypes();
        for(Type param:types){
            System.out.println(param);
            if(param instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) param).getActualTypeArguments();
                for(Type ata :actualTypeArguments){
                    System.out.println("    " +ata);
                }
            }

        }
        //定义一个泛型
        List<Integer> list = new ArrayList<>();
        list.add(123);
        list.add(245);
        System.out.println(list);

		//使用反射突破泛型限制
        Class clazz1 = list.getClass();
        Method method = clazz1.getMethod("add",Object.class);
        method.invoke(list,true);
        method.invoke(list,"dsr");
        method.invoke(list,3.14);
        System.out.println(list);

        //如何使用反射获取数组元素类型
        int[] arr = new int[10];
        Class clazz2 = arr.getClass();
        Class componentType = clazz2.getComponentType();
        System.out.println(componentType);


    }
}


举例我在实际项目中应用反射:

@Slf4j
public class BeanUtil {

    /**
     * T transfer R
     * @param sourceObject
     * @param targetClass
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> T convertObject(R sourceObject, Class<T> targetClass) {
        try {
            if (ObjectUtils.isEmpty(sourceObject)) {
                return null;
            }
            T t = targetClass.newInstance();
            BeanUtils.copyProperties(sourceObject, t);
            return t;
        } catch (Exception e) {
            log.error("convert object error,targetClass:{}", targetClass.getName(), e);
            throw new RuntimeException("convert object error",e);
        }
    }

    /**
     * list<T>  convert to list<R>
     *
     * @param sourceObjectList
     * @param targetClass
     * @param <T>              输入类型
     * @param <R>              输出 类型
     * @return list<R>
     */
    public static <T, R> List<R> convertObjectList(Collection<T> sourceObjectList, Class<R> targetClass) {
        if (CollectionUtils.isEmpty(sourceObjectList)) {
            return null;
        }
        List<R> result = sourceObjectList.stream().map(sourceObject -> {
            return convertObject(sourceObject, targetClass);
        }).collect(Collectors.toList());
        return result;
    }

    /**
     * T transfer R
     *
     * @param sourceObject 输入
     * @param targetClass  输出
     * @param consumer     对目标对象进行额外操作:比如赋值等
     * @param <T>          输入类型
     * @param <R>          输出 类型
     * @return R
     */
    public static <T, R> R convertObject(T sourceObject, Class<R> targetClass, BiConsumer<T, R> consumer) {
        try {
            if (ObjectUtils.isEmpty(sourceObject)) {
                throw new RuntimeException("sourceObject must not null");
            }
            R r = targetClass.newInstance();
            BeanUtils.copyProperties(sourceObject, r);
            if (null != consumer) {
                consumer.accept(sourceObject, r);
            }
            return r;
        } catch (Exception e) {
            log.error("convert object error,targetClass:{}", targetClass.getName(), e);
            throw new RuntimeException("convert object error",e);
        }
    }

    /**
     * list<T>  convert to list<R>
     *
     * @param sourceObjectList 输入
     * @param targetClass      输入
     * @param <T>              输入类型
     * @param <R>              输出 类型
     * @param consumer         对目标对象进行额外操作:比如赋值等
     * @return list<R>
     */
    public static <T, R> List<R> convertObjectList(Collection<T> sourceObjectList, Class<R> targetClass, BiConsumer<T, R> consumer) {
        if (CollectionUtils.isEmpty(sourceObjectList)) {
            return null;
        }
        return sourceObjectList.stream().map(sourceObject -> convertObject(sourceObject, targetClass, consumer)).collect(Collectors.toList());
    }

    /**
     * 将bean String属性中的null转换为""
     * @param bean
     * @param <T>
     */
    public static <T> void nullToEmpty(T bean) {
        Field[] field = bean.getClass().getDeclaredFields();
        for (int j = 0; j < field.length; j++) {     //遍历所有属性
            String name = field[j].getName();    //获取属性的名字
            //将属性的首字符大写,方便构造get,set方法
            name = name.substring(0, 1).toUpperCase() + name.substring(1);
            String type = field[j].getGenericType().toString();    //获取属性的类型
            if (type.equals("class java.lang.String")) {   //如果type是类类型,则前面包含"class ",后面跟类名
                try {
                    Method mGet = bean.getClass().getMethod("get" + name);
                    String value = (String) mGet.invoke(bean);    //调用getter方法获取属性值
                    if (value == null || "".equals(value)) {
                        Method mSet = bean.getClass().getMethod("set" + name, new Class[]{String.class});
                        mSet.invoke(bean, new Object[]{new String("")});
                    }
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值