最近在补Java基础,看到了类型信息这块知识,记起某些Android api和一些库里都有用到反射或动态代理的知识,特此探究一番。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Unknownclass {
private static String mClassName;
public static void main(String[] args) throws ClassNotFoundException{
Scanner in = new Scanner(System.in);
mClassName = in.nextLine();
Class c = Class.forName(mClassName); //mClassName 模拟动态获取的类
Method[] methods = c.getDeclaredMethods();
System.out.println("类"+mClassName+"的所有方法:");
for(Method method : methods){
System.out.println(method+"");
}
Constructor[] constructors = c.getConstructors();
System.out.println("类"+mClassName+"的所有构造方法:");
for(Constructor construct : constructors){
System.out.println(construct+"");
}
}
public void method1(String s1){
}
public void method2(){
}
}
打印结果:
Unknownclass //输入
类Unknownclass的所有方法:
public static void Unknownclass.main(java.lang.String[]) throws java.lang.ClassNotFoundException
public void Unknownclass.method2()
public void Unknownclass.method1(java.lang.String)
类Unknownclass的所有构造方法:
public Unknownclass()
获取到class引用后可以动态地newInstance出该类型的对象,并通过invoke方法调用其成员方法等等。
其实花费很多功夫,最后完成的操作可能也就是构造一个对象,访问下域调用下方法,利用反射机制无疑降低了程序的性能,增加了程序的复杂度,但前面也说了,它可以加载、探知、使用编译期间完全未知的classe,使程序可以有一定的动态性和通用性,所以用得好的话很犀利,用不好就弄巧成拙了。
总结:反射机制用于在程序运行时获得任意对象的类型的所有信息,构造任意类型的对象并可调用其方法访问其域。动态代理就是基于反射机制实现的。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args){
AnInterface proxy = (AnInterface)Proxy.newProxyInstance(AnInterface.class.getClassLoader(),
new Class[]{AnInterface.class}, new DynamicProxyHandler(new ActualObject()));
//构造动态代理对象并转换为某接口类型以调用接口声明的方法
proxy.method1("haha");
proxy.method2();
}
}
interface AnInterface{
void method1(String s1);
void method2();
}
class ActualObject implements AnInterface{
public void method1(String s1) {
System.out.println("调用了method2, 参数: " + s1);
}
public void method2() {
System.out.println("调用了method2");
}
}
class DynamicProxyHandler implements InvocationHandler{
private Object proxied; //实际使用的对象
public DynamicProxyHandler(Object proxied){
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备调用方法: " + method + " 参数:" + args);
return method.invoke(proxied, args); //动态调用某方法
}
}
打印结果:
准备调用方法: public abstract void AnInterface.method1(java.lang.String) 参数:[Ljava.lang.Object;@75b84c92
调用了method2, 参数: haha
准备调用方法: public abstract void AnInterface.method2() 参数:null
调用了method2
分析可知,proxy作为一个代理,相当于保持了一个对实际对象的引用,同样通过代理这个中间人来操作实际对象。
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h); //检查传入的调用处理器是否为空
final Class>[] intfs = interfaces.clone();
......
Class> cl = getProxyClass0(loader, intfs);
......
final Constructor> cons = cl.getConstructor(constructorParams); //利用反射机制
return cons.newInstance(new Object[]{h}); //返回传入调用处理器构造的某个接口类型的对象,并向上转为Object
......
}
AnInterface proxy = (AnInterface)Proxy.newProxyInstance(AnInterface.class.getClassLoader(),
new Class[]{AnInterface.class}, new DynamicProxyHandler(new ActualObject()));
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备调用方法: " + method + " 参数:" + args);
return method.invoke(proxied, args); //动态调用某方法
}