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方法的结果是:你大爷啊啊啊

最新文章

  1. JavaWeb结合七牛云存储搭建个人相册服务
  2. 关于Kendo的Grid 单元格样式
  3. Grandpa&#39;s Estate---POJ1228(凸包)
  4. [原]OpenGL基础教程(五)缓冲区数据更新方式
  5. Intellij IDEA-can&#39;t use subversion command line client : svn
  6. Windows服务器nginx+tomcat服务负载均衡
  7. seajs教程之seajs学习笔记 seajs.use用法
  8. bin文件格式分析
  9. 支付顺序--&gt;微信支付到公司账户--&gt;待出票
  10. PS2键盘 + LCD12864 实验
  11. 【EasyNetQ】- 发布/订阅模式
  12. 2018-12-03 VS Code英汉词典插件v0.0.7-尝试词性搭配
  13. Linux中各个目录作用
  14. asp.net上传图片,上传图片
  15. .net core使用配置文件
  16. python学习之旅(六)
  17. Exception analysis
  18. gulp_css2js
  19. 通过C#的HttpClient模拟form表单请求
  20. G1 Garbage Collector and Shenandoah

热门文章

  1. 华为云函数中使用云数据库的JavaScript SDK基础入门
  2. 用工具堆砌的DevOps 幻觉
  3. Jenkins远程发布制品
  4. [BUUCTF]REVERSE——[V&N2020 公开赛]CSRe
  5. 【译】使用 Visual Studio 调试外部源代码
  6. Tornado 的安全性保障机制Cookie XSRF跨站请求伪造阻断 &amp;用户验证机制
  7. 使用iframe内嵌PC网站实现高度自适应
  8. js(JQuery)引入select2
  9. Android 控件使用教程(二)—— RecyclerView 展示图片
  10. 【剑指Offer】矩阵覆盖 解题报告(Python)