1.什么是JAVA的反射机制
Java的反射机制是指在运行时,可以获取、检查和操作类、对象、方法、字段等程序的内部信息的能力。反射机制使得程序可以动态地获取类的信息、实例化对象、调用方法、访问和修改字段等,而无需在编译时明确知道这些信息。反射机制为Java提供了灵活性和可扩展性,但也需要谨慎使用,因为它会牺牲一些性能和类型安全。
2.提供了什么功能
反射机制的核心类是`java.lang.Class`,它代表一个Java类的元数据。通过`Class`类,可以执行以下操作:
1. **获取类的信息:** 可以获取类的名称、包信息、父类、接口、方法、字段等信息。
2. **实例化对象:** 可以通过类的构造器来实例化对象,即使在编译时无法确定具体的类。
3. **调用方法:** 可以调用类中的方法,包括私有方法,也可以传递参数执行方法。
4. **访问和修改字段:** 可以访问和修改对象的字段,包括私有字段。
5. **处理数组:** 可以创建、访问和修改数组对象。
反射机制通常用于以下情况:
- 开发通用性高的框架和工具,例如ORM(对象关系映射)库、依赖注入容器等。
- 编写调试工具和性能分析工具。
- 处理配置文件,动态加载类和资源。
- 在特殊情况下,需要与不可知类型的对象交互。
虽然反射提供了强大的能力,但也需要注意一些潜在问题,如性能开销、类型安全性、编译时检查的缺失等。因此,在使用反射时需要小心谨慎,确保合理使用,并且尽量避免破坏封装性和类型安全性。
3.JDK中提供的Reflection API
JDK中提供了一组用于反射的API,这些API允许你在运行时获取和操作类、方法、字段、构造器等元数据信息。以下是主要的Reflection API类和接口:
1. `java.lang.Class`:代表一个Java类或接口的元数据信息。它是反射的入口点之一,用于获取类的各种信息。
- `getName()`:获取类的全限定名。
- `getSuperclass()`:获取父类的Class对象。
- `getInterfaces()`:获取实现的接口数组。
- `getDeclaredMethods()`:获取声明的方法数组。
- `getDeclaredFields()`:获取声明的字段数组。
- 等等。
2. `java.lang.reflect.Method`:代表类的方法,可以用于获取和调用类的方法。
- `getName()`:获取方法名。
- `getParameterTypes()`:获取方法的参数类型数组。
- `invoke(Object obj, Object... args)`:调用方法。
- 等等。
3. `java.lang.reflect.Field`:代表类的字段,可以用于获取和设置类的字段值。
- `getName()`:获取字段名。
- `getType()`:获取字段的类型。
- `get(Object obj)`:获取字段的值。
- `set(Object obj, Object value)`:设置字段的值。
- 等等。
4. `java.lang.reflect.Constructor`:代表类的构造器,可以用于实例化对象。
- `getParameterTypes()`:获取构造器的参数类型数组。
- `newInstance(Object... initargs)`:创建类的实例。
- 等等。
这些API允许你在运行时执行各种操作,如创建对象、调用方法、访问字段等,而不需要在编译时了解类的具体信息。反射是一种非常强大但也复杂的特性,需要小心使用,以确保类型安全和性能。
4.在动态代理中使用反射
1、定义抽象角色
public interface Subject {
public void Request();
}
2、定义真实角色
public class RealSubject implements Subject {
@Override
public void Request() {
// TODO Auto-generated method stub
System.out.println("RealSubject");
}
}
3、定义代理角色
public class DynamicSubject implements InvocationHandler {
private Object sub;
public DynamicSubject(Object obj){
this.sub = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("Method:"+ method + ",Args:" + args);
method.invoke(sub, args);
return null;
}
}
4、通过Proxy.newProxyInstance构建代理对象
RealSubject realSub = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSub);
Class<?> classType = handler.getClass();
Subject sub = (Subject)Proxy.newProxyInstance(classType.getClassLoader(),
realSub.getClass().getInterfaces(), handler);
System.out.println(sub.getClass());
5、通过调用代理对象的方法去调用真实角色的方法。
sub.Request();
输出:
class $Proxy0 新建的代理对象,它实现指定的接口
Method:public abstract void DynamicProxy.Subject.Request(),Args:null
RealSubject 调用的真实对象的方法