Java反射与动态代理
1.Java反射
当通过反射与一个未知类型的对象打交道时,JVM只简单地检查这个对象,看它属于哪个特定的类。在用它做其他事情之前必须先加载那个类的Class对象。
当使用反射时,就可以在运行时获取类信息,对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
下面就是一个反射的例子,通过反射输出了该类的所有方法和构造器,然后通过反射调用了该类的方法。从输出结果可以看出,通过反射获取到了运行类的所有方法信息和构造函数信息,还通过反射机制调用了该类的方法,进行了输出。
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
public class ShowMethods {
private static String usage = "usage";
private static Pattern p = Pattern.compile("\\w+\\.");
public void method1() {
System.out.println("我被调用啦");
}
public void method2(int num) {
System.out.println(num);
}
public static void main(String[] args) {
try {
ShowMethods showMethods = new ShowMethods();
System.out.println(showMethods.getClass().getName());
// 加载该类
Class<?> c = Class.forName("reflect.ShowMethods");
// 获取该类所有的方法
Method[] methods = c.getMethods();
// 获取该类所有的构造函数
Constructor[] constructors = c.getConstructors();
for (Method method : methods) {
System.out.println(p.matcher(method.toString()).replaceAll(" "));
}
for (Constructor constructor : constructors) {
System.out.println(p.matcher(constructor.toString()).replaceAll(" "));
}
// 获取该类的method1方法
Method method1 = c.getMethod("method1");
// 调用无参方法
method1.invoke(c.newInstance());
// 获取该类的method2方法
Method method2 = c.getMethod("method2", int.class);
// 调用有参方法,传入参数20
method2.invoke(c.newInstance(), 20);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
输出结果如下:
reflect.ShowMethods
public static void main( String[])
public void method1()
public void method2(int)
public final void wait() throws InterruptedException
public final void wait(long,int) throws InterruptedException
public final native void wait(long) throws InterruptedException
public boolean equals( Object)
public String toString()
public native int hashCode()
public final native Class getClass()
public final native void notify()
public final native void notifyAll()
public ShowMethods()
我被调用啦
20
2.代理模式
静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
Subject接口
public interface Subject {
void request();
}
RealSubject类
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject");
}
}
代理类
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
System.out.println("begin");
subject.request();
System.out.println("end");
}
}
测试类
public class ProxyTest {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.request();
}
}
动态代理
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
同样实现上面的结构。
public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
public void doSomething() {
System.out.println("我正在做某事");
}
}
代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SubjectProxy implements InvocationHandler {
private Object target;
public SubjectProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("begin");
Object result = method.invoke(target, args);
System.out.println("end");
return result;
}
public Object getProxy() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(classLoader, interfaces, this);
}
}
public class SubjectTest {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
SubjectProxy subjectProxy = new SubjectProxy(realSubject);
Subject subject = (Subject)subjectProxy.getProxy();
subject.doSomething();
}
}
优点:动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。
不足:始终无法摆脱仅支持 interface 代理的桎梏。