一、背景
最近又看了下java反射的一些东西,所以简单汇总记录一下.
二、关于java反射
2.1、什么是java反射
① 反射是一种动态获取信息及调用对象的一种机制。
② 对于一个在运行中的java类,我们都可以知道它的所有属性和方法。
③ 对于一个在运行状态中的对象,我们也都能通过反射来调用它的任意方法已经属性的调用及改变
2.2、什么情况下会用到反射
① 一般来说我们在日常开发中直接用到反射的地方不多,它更多用于框架的开发
② 不能明确接口调用的是哪个函数,需要根据传入参数再运行时决定。
③ 不能明确传入函数的参数类型,但是又需要再运行时处理任意对象
2.3、反射给我们提供了那些支持
① Class.forName(String className): 返回给定字符串名称的类或接口的相关类对象
② getDeclaredConstructors():返回一个数组,包含类的公共构造函数
③ getConstructor(Class<?>, paremeterTypes):返回指定反射类的指定入参类型的构造函数
④ getDeclaredMethos():返回一个数组,包含反射类的所有公共、保护、私有、默认方法(不包括继承的方法)
⑤ getDeclaredFields():返回一个数组,包含反射类的所有字段属性
⑥ getDeclaredField(String fieldName): 返回反射类指定名称的字段属性
⑦ getMethods(): 返回一个数组,包含反射类的公共方法,包含继承的方法
⑧ getMethod(String name, Class<?>, paremeteraTypes): 返回反射类指定的公共成员方法
PS:更多信息,请参考官方文档。
三、代码示例
@Data
public class Person {
private String name;
private int age;
public Person(){
System.out.println("我是默认构造方法,我被调用了!");
}
public Person(String name, int age){
System.out.println("有参构造 --- 姓名为:" + name + " 年龄为:" + age);
}
}
import com.example.easyexcel.model.Person;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Test
{
public static void main(String args[]) throws IllegalArgumentException, IllegalAccessException, ClassNotFoundException,
NoSuchMethodException, InvocationTargetException, InstantiationException, NoSuchFieldException {
System.out.println("通过反射调用类的默认构造方法");
Class person = Class.forName("com.example.easyexcel.model.Person");
Constructor constructor = person.getConstructor(null);
constructor.newInstance(null);
System.out.println("通过反射调用类的有参构造方法");
Constructor constructor1 = person.getConstructor(String.class, int.class);
constructor1.newInstance("XiaoMing", 19);
System.out.println("======================================");
Person bean = new Person();
bean.setName("ZZSS");
Field[] fields = bean.getClass().getDeclaredFields();
Field field = bean.getClass().getDeclaredField("name");
field.setAccessible(true);
Object objectName = field.get(bean);
System.out.println("获取指定字段name的值为:" + objectName);
System.out.println("======================================");
for(int i = 0;i < fields.length;i++){
Field fieldTmp = fields[i];
// 设置属性是可以访问的
fieldTmp.setAccessible(true);
// 得到此属性的值
Object valTmp = fieldTmp.get(bean);
String type = fieldTmp.getType().toString();
System.out.println("字段类型为:" + type);
System.out.println("属性名:" + fieldTmp.getName());
System.out.println("属性值:" + valTmp);
System.out.println("======================================");
// 得到此属性的类型
if(type.endsWith("String"))
{
// 给属性设值
fieldTmp.set(bean,"LFG");
}
else if(type.endsWith("int") || type.endsWith("Integer"))
{
// 给属性设值
fieldTmp.set(bean,121);
}
}
System.out.println("重新设值后的对象属性为:"+bean.getName()+" "+bean.getAge());
}
}
Java
程序输出如下:
通过反射调用类的默认构造方法
我是默认构造方法,我被调用了!通过反射调用类的有参构造方法有参构造 --- 姓名为:XiaoMing 年龄为:19======================================我是默认构造方法,我被调用了!获取指定字段name的值为:ZZSS======================================字段类型为:class java.lang.String属性名:name属性值:ZZSS======================================字段类型为:int属性名:age属性值:0======================================重新设值后的对象属性为:LFG 121
四、日志模块中部分代码示例
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogEntity sysLog = new SysLogEntity();
SysLog syslog = method.getAnnotation(SysLog.class);
if (syslog != null) {
// 注解上的描述
sysLog.setOperation(syslog.value());
}
// 请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
// 请求的参数
Object[] args = joinPoint.getArgs();
try {
String params = new Gson().toJson(args[0]);
sysLog.setParams(params);
。。。
} catch (Exception e) {
}
// 获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
// 设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
。。。
sysLogApi.saveLog(sysLog);
}
Java
PS: 可以参见:Springboot自定义注解日志管理实现