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