1.前言
什么是反射?
引用教科书的解释:
在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
如何通俗理解?
其实说白了,就是将任意一个类对象【原对象】注入一个反射类里,可以对原对象解析,
获取里面的所有属性和方法信息,并可以调用;使用原对象获取对象类型后获取无参构造函数再实例一个无参对象,
那么这个对象就是该原对象的反射对象,反射对象有着与原对象一样的属性和方法,可以动态获取任意对象信息和动态的调用任意对象方法,
如果不做其他增强操作,就相当于反射对象复制了原对象。
由此可见,可以调用原方法的同时做一些其他操作,也就是增强操作,这也就是动态代理的底层原理。
2.操作
使用代码理解【里面有很多注释,足够理解了啊】
(1)文件目录结构
(2)建一个实体类
package com.example.javabaisc.reflect.deme; import java.util.HashMap; import java.util.UUID; /** * 实体类 */ public class Info { //被保护的属性 private int id; private String name; //无参构造函数 public Info(){}; //有参构造函数 public Info(int id ,String name){ this.id = id ; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } //共有自定义方法 public String dosomething(String str){ System.out.println("我是自定义方法,输入参数是="+str); return str+"==="+ UUID.randomUUID().toString(); } //私有被保护的自定义方法 private String love(int num){ System.out.println("我是自定义方法,输入参数是="+num); return num+"==="+ UUID.randomUUID().toString(); } //公共使用属性 public String publicParam; }
有各种属性和方法
(3)反射类
package com.example.javabaisc.reflect.deme; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * 反射类 */ public class DoReflect { Logger logger = LoggerFactory.getLogger(getClass()); /* 反射方法【类似于复制操作】 */ public Object copy(Object object) throws Exception { /** * 获取传入原对象的类型 */ // 写法1:【泛型可写可不写】 Class<?> classType = object.getClass(); logger.warn("获取传入原对象的类型:" + classType.getName()); //写法2: //原对象的文件路径【注意,没有文件java后缀,不建议这样使用,否则需要传入路对象文件路径】 // String infoURL = "com.example.javabaisc.reflect.deme.Info"; // Class<? > classType = Class.forName(infoURL); // //写法3: //原对象的文件路径【不建议这样使用,否则需要传入路对象文件路径】 // String infoURL = "com.example.javabaisc.reflect.deme.Info"; // Class<?> classType = DoReflect.class.getClassLoader().loadClass(infoURL); // //看看,方法2和3 是不是很眼熟,就是以前使用原生的jdbc连接数据库放入操作啊,原来jdbc底层是使用了映射。。。 //但是还是方法1简单,而且容易理解 // // /** * 根据原对象类型,获取无参构造函数后实例一个新的对象,这个就是映射对象 */ //如果newInstance没有参数,则可以不写空的超类数组 Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); // //上面一句话可以分步写: // //步骤1:获取无参构造函数对象 // Constructor<?> constructor = classType.getConstructor(new Class[]{}); // logger.warn("无参构造函数对象名字:" + constructor.getName()); // //步骤2:获反射对象 // Object objectCopy = constructor.newInstance(new Object[]{}); logger.warn("反射对象名字:" + objectCopy.toString()); // /** * 获取所有方法 */ Method[] methods = classType.getDeclaredMethods(); logger.warn("==================================================================="); for (Method method : methods) { /* 获取方法修饰符 */ String modifier = Modifier.toString(method.getModifiers()); logger.warn("获取方法修饰符:" + modifier); /* 获取返回参数类型 */ // [会获取完整的类型路径名,如 java.lang.String] String returnType = method.getReturnType().getName(); logger.warn("获取返回参数类型,写法1:" + returnType); // [仅会获取名字,如String] String returnType2 = method.getReturnType().getSimpleName(); logger.warn("获取返回参数类型,写法2:" + returnType2); /* 获取方法名字 */ String methodName = method.getName(); logger.warn("获取方法名字:" + methodName); //获取所有传入参数类型 Class<?>[] params = method.getParameterTypes(); logger.warn("------------------------------------------------------------"); for (Class<?> param : params) { /* 获取参数类型名字 */ //写法1和2都是获取完整的类型路径名,如 java.lang.String String paramTypeName = param.getName(); String paramTypeName2 = param.getTypeName(); //该写法3仅会获取类型名字,如String String paramTypeName3 = param.getSimpleName(); logger.warn("获取参数类型名字,写法1:" + paramTypeName); logger.warn("获取参数类型名字,写法2:" + paramTypeName2); logger.warn("获取参数类型名字,写法3:" + paramTypeName3); } logger.warn("------------------------------------------------------------"); } logger.warn("==================================================================="); /** * 获取指定的方法 */ logger.warn("使用getMethod获取指定的方法,但是仅能获取public修饰的方法"); //参数分别是 方法名字 、参数类型 Method method = classType.getMethod("dosomething", new Class[]{String.class}); // 指定方法的修饰符 String modifier = Modifier.toString(method.getModifiers()); logger.warn("指定方法的修饰符:" + modifier); String returnTypeName = method.getReturnType().getSimpleName(); logger.warn("指定方法的返回类型:" + returnTypeName); //指定方法的名子 String methodName = method.getName(); logger.warn("指定方法的名子:" + methodName); Class<?>[] params = method.getParameterTypes(); for (Class<?> param : params) { logger.warn("指定方法的参数类型:" + param.getSimpleName()); } logger.warn("==================================================================="); logger.warn("使用privateMethod获取指定的方法,可以获取被保护的方法"); //参数分别是 方法名字 、参数类型 Method privateMethod = classType.getDeclaredMethod("love", new Class[]{int.class}); // 指定方法的修饰符 String modifier2 = Modifier.toString(privateMethod.getModifiers()); logger.warn("指定方法的修饰符:" + modifier2); String returnTypeName2 = privateMethod.getReturnType().getSimpleName(); logger.warn("指定方法的返回类型:" + returnTypeName2); //指定方法的名子 String methodName2 = privateMethod.getName(); logger.warn("指定方法的名子:" + methodName2); Class<?>[] params2 = privateMethod.getParameterTypes(); for (Class<?> param : params2) { logger.warn("指定方法的参数类型:" + param.getSimpleName()); } logger.warn("==================================================================="); /** * 获取所有属性 */ logger.warn("获取所有属性"); Field[] fields = classType.getDeclaredFields(); logger.warn("------------------------------------------------------------"); for (Field field : fields) { //属性修饰符 String modifer = Modifier.toString(field.getModifiers()); logger.warn("属性修饰符:" + modifer); //属性类型 String fieldType = field.getType().getSimpleName(); logger.warn("属性类型:" + fieldType); //属性名字 String fieldName = field.getName(); logger.warn("字段名字:" + fieldName); } logger.warn("------------------------------------------------------------"); logger.warn("==================================================================="); /** * 获取指定属性 */ logger.warn("使用getField获取指定属性,但是仅能获取public修饰的属性"); Field field = classType.getField("publicParam"); //属性修饰符 String modifer = Modifier.toString(field.getModifiers()); logger.warn("属性修饰符:" + modifer); //属性类型 String fieldType = field.getType().getSimpleName(); logger.warn("属性类型:" + fieldType); //属性名字 String fieldName = field.getName(); logger.warn("字段名字:" + fieldName); logger.warn("------------------------------------------------------------"); logger.warn("使用getDeclaredField获取指定属性,可以获取被保护的属性"); Field field2 = classType.getDeclaredField("id"); //属性修饰符 String modifer2 = Modifier.toString(field2.getModifiers()); logger.warn("属性修饰符:" + modifer2); //属性类型 String fieldType2 = field2.getType().getSimpleName(); logger.warn("属性类型:" + fieldType2); //属性名字 String fieldName2 = field2.getName(); logger.warn("字段名字:" + fieldName2); logger.warn("==================================================================="); /** * 调用对象的方法, * 首先需要获取方法对象,然后通过参数来选择是调用原对象的方法还是反射对象的方法 */ logger.warn("调用对象的方法"); /* 向原对象 setname 传入name值,然后 getname 获取原对象name值,然后将获取的值使用反射对象的 setname 方传入后,使用反射对象的 getname 获取 */ //拼接 setname 方法名字 String setMethodName = "set" + ("name".substring(0, 1).toUpperCase()) + ("name".substring(1)); //拼接 getname 方法名字 String getMethodName = "get" + ("name".substring(0, 1).toUpperCase()) + ("name".substring(1)); //获取 setname 方法对象 Method setMethod = classType.getDeclaredMethod(setMethodName, new Class[]{String.class}); //获取 getname 方法对象 Method getMethod = classType.getDeclaredMethod(getMethodName, new Class[]{}); //调用原对象的 setname方法,并赋值 String mname = "你大爷啊啊啊"; setMethod.invoke(object, new Object[]{mname}); //调用原对象的 getname方法 获取name值 Object value = getMethod.invoke(object, new Object[]{}); logger.warn("调用 原对象 的 getname方法 获取name值为:" + value); //调用反射对象的 setname方法,并赋值 setMethod.invoke(objectCopy, new Object[]{value}); //调用反射对象的 getname方法 获取name值 Object reflectValue = getMethod.invoke(objectCopy, new Object[]{}); logger.warn("调用 反射对象 的 getname方法 获取name值为:" + reflectValue); logger.warn("==================================================================="); //返回反射对象 return objectCopy; } }
(4)测试类
package com.example.javabaisc.reflect.deme; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 测试类 */ public class RETest { Logger log = LoggerFactory.getLogger(getClass()); @Test public void t() throws Exception { //实例实体类 Info info = new Info(); //实例反射类 DoReflect doReflect = new DoReflect(); //调用反射类的反射方法,将实体类对象注入进去 ,返回这个实体类的反射对象 Info infoReflect = (Info) doReflect.copy(info); //调用反射对象的方法 String res = infoReflect.dosomething("扫地啦"); log.warn("调用反射对象的方法的结果是:{}",res); //调用反射对象的getname方法[已经在反射方法了做了赋值操作] String name = infoReflect.getName(); log.warn("调用反射对象的getname方法的结果是:{}",name); } }
3.测试
运行测试类,控制台打印
16:16:40.811 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取传入原对象的类型:com.example.javabaisc.reflect.deme.Info 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 反射对象名字:com.example.javabaisc.reflect.deme.Info@78a2da20 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:getName 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:int 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:int 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:getId 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:void 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:void 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:setName 16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:dosomething 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:private 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:love 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:void 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:void 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:setId 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getMethod获取指定的方法,但是仅能获取public修饰的方法 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的修饰符:public 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的返回类型:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的名子:dosomething 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的参数类型:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用privateMethod获取指定的方法,可以获取被保护的方法 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的修饰符:private 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的返回类型:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的名子:love 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的参数类型:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取所有属性 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:int 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:id 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:name 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:public 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:publicParam 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getField获取指定属性,但是仅能获取public修饰的属性 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:public 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:publicParam 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------ 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getDeclaredField获取指定属性,可以获取被保护的属性 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:int 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:id 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用对象的方法 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用 原对象 的 getname方法 获取name值为:你大爷啊啊啊 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用 反射对象 的 getname方法 获取name值为:你大爷啊啊啊 16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - =================================================================== 我是自定义方法,输入参数是=扫地啦 16:16:41.085 [main] WARN com.example.javabaisc.reflect.deme.RETest - 调用反射对象的方法的结果是:扫地啦===fd1cfc80-e653-4661-9f06-77780f363a5d 16:16:41.087 [main] WARN com.example.javabaisc.reflect.deme.RETest - 调用反射对象的getname方法的结果是:你大爷啊啊啊