反射是什么?
反射是被视为动态语言的关键,反射机制允许程序在执行期借助于 ReflectionAPI 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射利用的类对象什么时候产生的?
这一部分需要了解类加载机制,第一阶段的加载,通过 Jar 包、网络、文件、动态编译等方式获取类的 Class 文件并读取内存,如果是 JDK 1.8 以前 Class文件被放入在堆中的方法区,而 JDK 1.8 以及以后, Class 文件被放在元数据区中,元数据区包含:运行时常量池,类元信息,方法元信息。
反射所能够提供的功能有哪些?
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时判断任意一个类所具有的成员变量和方法
4)在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法
5)在运行时处理注解生成动态代理
获取 Class 类实例的四种方法
1)调用运行时类的属性,.class
Class example = String.class;
2)通过运行时类的对象,调用 getClass()
Class example = String.getClass()
3)调用类的静态方法,forName(String classPath)
Class example = Class.forName("类的全路径")
4)调用类的加载器 ClassLoader
ClassLoader cl = this.getClass().getClassLoader();
Class example = cl.loadClass("全类名");
在有了类对象后,利用 newInstance() 方法即可获取实例。
前提是类必须由一个无参数的构造器而且构造器的访问权限必须足够。
如果实例需要有参构造器,那么需要利用 getConstructor 方法。
举个例子如下
Constructor ex = clazz.getConstructor(String.class,Integer.class);
Person p = (Person) ex.newInstance("Peter",20);
System.out.println(p);
同理,利用反射还可以获取类的属性结构,类的方法结构等等。对于私有属性,反射还可以利用 setAccessible(true) 进行爆破处理,直接访问私有属性和方法。因此会产生安全性的风险。
反射的应用场景
举个 JDK 动态代理时候的例子,经典。
method.invoke 是调用真正的方法,而这一点利用的正是反射机制。
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类的代理对象
UserDaoImpl userDao = new UserDaoImpl();
Class[] interfaces = {UserDao.class};
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result = " + result);
}
}
class UserDaoProxy implements InvocationHandler {
//1.把创建的是谁的代理对象,把谁传递过来
//有参数构造器
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前:
System.out.println("方法之前执行...." + method.getName() + ":传递的参数..." + Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行..." + obj);
return res;
}
}
反射的优缺点有哪些?
优点包括:
1)动态性:反射允许在运行时动态地获取和操作类的信息,而不需要在编译时知道类的具体细节。
2)灵活性:反射可以通过类名字符串来创建对象实例,可以在运行时动态地调用方法和字段,以及访问和修改私有成员。
3)扩展性:反射可以用于实现一些高级功能,如动态代理、注解处理和依赖注入等。
缺点包括:
1)性能损耗:由于反射需要在运行时获取和操作类的信息,所以相比直接调用,反射操作通常会导致性能下降。
2)安全问题:反射可以访问和修改私有成员,这可能破坏了封装性和安全性。因此,在使用反射时需要谨慎处理权限和访问控制。
3)编码复杂性:反射的使用和理解相对复杂,容易引入错误和难以调试。同时,反射操作也不受编译器的类型检查,可能导致运行时异常。
其他补充
反射是什么?反射是一种在运行时检查和操作类、方法、字段等程序结构的能力。在Java中,反射机制允许程序在运行时获取类的信息、构造对象、调用方法、访问字段等,而不需要在编译时就确定这些操作。
类对象何时产生?类对象是在类加载时产生的。当Java程序启动并加载类时,系统会为每个类产生一个对应的Class对象,该对象包含了类的结构信息,可以通过反射机制获取。
反射提供的功能有哪些?
1)获取类的信息: 获取类的名称、包信息、父类、实现的接口等。
2)实例化对象: 动态创建类的对象,而不是通过new
关键字。
3)获取和设置字段值: 通过反射可以访问类的字段,并在运行时动态设置或获取字段的值。
4)调用方法: 动态调用类的方法,包括私有方法。
5)操作数组: 创建、获取、设置数组的元素。
6)访问构造方法: 获取类的构造方法并实例化对象。
反射的应用场景:
1)框架和库设计: 许多框架和库在设计时使用反射来实现灵活的配置和扩展机制。
2)工具开发: 一些开发工具、IDE等利用反射机制来分析和操作代码。
3)注解处理器: 注解处理器通过反射机制读取和处理源代码中的注解信息。
4)测试工具: 测试工具可以使用反射来检查和调用类的私有方法。
反射的优缺点:
优点:
1)灵活性: 反射提供了对类结构的动态访问,使得程序在运行时更加灵活。
2)框架设计: 反射使得框架可以在不直接依赖特定类的情况下操作对象。
缺点:
1)性能开销: 反射操作相比直接调用代码会带来一定的性能开销,因为它需要在运行时进行类型检查和动态调用。
2)安全性问题: 反射可以越过访问控制,访问私有成员,这可能引发安全问题。
3)编译时检查缺失: 由于反射是在运行时进行的,编译器无法进行静态检查,容易引入运行时错误。
在使用反射时,需要谨慎考虑性能和安全性,并在合适的场景下使用。
反射流程图