反射
Java 类型信息的获取
RTTI(Run-Time Type-Identification)
Java程序运行时会有类型转换,因此需要在运行时获取类型信息来判断类型转换是否有效。
Java 反射机制
动态获取类信息以及动态调用对象的方法的功能称为Java的反射机制。
Object 类、 Class 类 Method 类
Object
Java中所有类都继承自Object类。拥有Object类的方法,例如:
- hashCode()
- equals()
- clone()
- toString()
- notify()
- wait()
Class
每当Java虚拟机装载一个新类时,都会在Java堆中创建一个Class实例,这个实例代表这个Class类型。以下为此类的一些方法,其中Method和Field也是Java中的类。
Method[] getMethods()Field[] getFields()Construct<?>[] getDeclaredConstructors()
Method类
使用Method类的invoke方法调用类方法,需要传入一个类实例,有参数也需要传参数。
通过反射创建一个类
public static class Apple{
@Override
public String toString(){
return "I am apple";
}
}
public static void main(String[] args) throws Exception {
Constructor<Apple> constructor = Apple.class.getDeclaredConstructor();
Apple one = constructor.newInstance();
System.out.println(one.toString());
}
通过反射调用一个类的方法
public static class Apple{
public String sayHello(){
return "Hello";
}
public String hello(String toOne){
return "Hello " + toOne;
}
}
public static void main(String[] args) {
try {
Apple apple = new Apple();
Class<?> cls = apple.getClass();
Method method = cls.getMethod("hello", String.class);
System.out.println(method.invoke(apple,"me"));
}catch (Exception e){
e.printStackTrace();
}
}
代理
有时候不能直接引用某个对象,而想要间接访问某个对象。代理就是提供了间接访问某个对象的功能。
代理中的角色:
- 抽象角色:真实角色和代理角色都有的接口。
- 真实角色:被代理的角色,真正访问的对象。
- 代理角色:代理真实角色的角色,提供了访问真实角色的方法,通过代理可以间接访问真实角色。
静态代理
private interface comAction{
void sayHello();
}
private static class realActor implements comAction{
@Override
public void sayHello() {
System.out.println("Hello the World, I am the real Actor");
}
}
private static class proxyActor implements comAction{
private final realActor ra;
proxyActor(){
this.ra = new realActor();
}
@Override
public void sayHello() {
beforeSayHello();
ra.sayHello();
afterSayHello();
}
public void beforeSayHello(){
System.out.println("Before say hello");
}
public void afterSayHello(){
System.out.println("After say hello");
}
}
public static void main(String[] args) {
proxyActor pa = new proxyActor();
pa.sayHello();
}
动态代理
Java.lang.reflect.proxy 提供了一组静态方法来为一组接口实现代理类和其对象。
- 代理对象关联的调用处理器:getInvocationHandler( Object proxy)
- 关联于指定类的装载器和一组动态接口的代理类的类对象:getProxyClass(ClassLoader cl,Class [] interfacces)
- 判断是否为一个动态代理类:isProxy(Class cl)
- 为给定的类装载器、动态接口的代理类和调用处理器生成动态代理类实例:newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler h)
动态代理与包的位置:如果代理的接口是public,那么代理类应该定义在最顶层包,如果非public,则应该将代理类定义在接口所定义的位置。这样做以解决代理类和包的管理导致的问题。
代理类不应该被继承,应使用final修饰符修饰。
对于一对相同的接口(包括顺序相同),JVM不会创建两次代理类,会返回上一次的代理类。
// 定义一个接口
interface Subject {
void request();
}
// 实现接口的类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 创建InvocationHandler实现类
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用之前执行一些操作
System.out.println("Before method: " + method.getName());
// 调用原始方法
Object result = method.invoke(target, args);
// 在方法调用之后执行一些操作
System.out.println("After method: " + method.getName());
return result;
}
}
public class C5experimentApplication {
public static void main(String[] args) {
// 创建目标对象
RealSubject realSubject = new RealSubject();
// 创建InvocationHandler
InvocationHandler handler = new MyInvocationHandler(realSubject);
// 创建代理对象
Subject subject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
new Class[]{Subject.class},
handler);
// 调用代理对象的方法
subject.request();
}
}