一、简介
百度百科:Java反射机制实在运行状态中,对任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意的方法和属性,这种动态获取信息以及动态调用对象的方法的功能成为Java语言的反射机制。
适用场景:在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架,也是利用CGLIB 反射机制才得以实现,其中运用最多的场景是JDBC 的数据库的连接。
反射机制的优点:
- 降低模块的耦合性,提高程序灵活性、扩展性。
反射机制的缺点:
- 性能差:反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率比非反射操作低很多。在执行代码效率很高的程序中要避免使用反射。
- 安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行。
- 内部暴漏:由于反射允许执行一些在正常情况下不被允许的操作(比如访问私有属性和方法),所以使用反射可能会导致意料之外的副作用——代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着改变。
二、Java代码实现
插件类PlugIn
package net.jinglong.demo1;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PlugIn {
private String time;
private String timeFormat;
public String getTime() {
if (timeFormat != null) {
SimpleDateFormat df = new SimpleDateFormat(timeFormat); //设置日期格式
System.out.println(df.format(new Date())); //new Date()为获取当前系统时间
time = df.format(new Date());
}else {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式
System.out.println(df.format(new Date())); //new Date()为获取当前系统时间
time = df.format(new Date());
}
return time;
}
public void setTimeFormat(String timeFormat) {
this.timeFormat = timeFormat;
}
public String getTimeFormat() {
return timeFormat;
}
}
调用入口
package net.jinglong.demo1;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Demo {
public static void main(String[] args) throws Exception {
//获取PlugIn的Class对象
//1、通过Class.forName()方法加载字符串,就可以得到该字符串做代表的Class对象
Class<?> clazz = Class.forName("net.jinglong.demo1.PlugIn");
//获取该类中的所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));
System.out.println("类型:" + field.getType());
System.out.println("属性名:" + field.getName());
}
//获取该类中的所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// System.out.println(method);
// System.out.println("修饰符:" + Modifier.toString(method.getModifiers()));
// System.out.println("方法名:" + method.getName());
// System.out.println("返回类型:" + method.getReturnType());
Class<?>[] clazzes = method.getParameterTypes();
for (Class<?> class1 : clazzes) {
// System.out.println("参数类型:" + class1);
}
}
//通过Class对象创建对象
PlugIn plugIn = (PlugIn) clazz.newInstance();
//获取属性名为timeFormat的字段对象,重新设置值
Field timeFormat = clazz.getDeclaredField("timeFormat");
//字段属性为private,设置为可以访问
timeFormat.setAccessible(true);
//设置timeFormat的值
timeFormat.set(plugIn, "yyyy-MM-dd");
//通过Class对象获取名为getTime、无参数类型的方法对象
Method empty = clazz.getDeclaredMethod("getTime");
//方法属性为private,设置为可以访问
empty.setAccessible(true);
//调用empty()方法
empty.invoke(plugIn);
}
}
显示结果
private java.lang.String net.jinglong.demo1.PlugIn.time
修饰符:private
类型:class java.lang.String
属性名:time
private java.lang.String net.jinglong.demo1.PlugIn.timeFormat
修饰符:private
类型:class java.lang.String
属性名:timeFormat
2019-11-19
当禁调timeFormat写入代码块,调用结果如下
private java.lang.String net.jinglong.demo1.PlugIn.time
修饰符:private
类型:class java.lang.String
属性名:time
private java.lang.String net.jinglong.demo1.PlugIn.timeFormat
修饰符:private
类型:class java.lang.String
属性名:timeFormat
2019-11-19 20:32:07