一.java反射主要有哪些功能?
在代码运行时,可以获取任意一个类的所有属性和方法、以及类和方法上的注解,还可以调用这些方法和注解。
二.java反射有哪些应用场景?为什么要用反射?
在日常的业务代码编写中,反射可能用的比较少,直接使用类的属性和方法比较多。但是在开发框架时,大量用到了反射机制。因为在编写框架时,我们无法知道使用该框架的业务场景都有哪些对象,框架只是提供了通用的功能,所以要用反射来动态获取具体的业务对象。应用场景:注解、Mybatis等
三.反射和代理有什么关系?
代理模式是一种设计模式,而反射是实现动态代理的一种方法。比如动态代理中的Method.invoke方法就使用了反射。
四.一个demo理顺jdk动态代理的执行过程?
一个接口:
public interface SendMsg{
public void send(String msg);
}
一个实现类:
public class SendMsgImpl implements SendMsg{
public void send(String msg){
System.out.println("发送"+msg);
}
}
写一个动态代理类,里面包含要额外添加的逻辑:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DebugInvocationHandler implements InvocationHandler {
/*代理类中的真实对象 */
private final Object target;
public DebugInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
//调用方法之前,我们可以添加自己的操作
System.out.println("before method " + method.getName());
Object result = method.invoke(target, args);
//调用方法之后,我们同样可以添加自己的操作
System.out.println("after method " + method.getName());
}
}
写一个获取代理对象的工厂类
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler
);
}
}
实际使用:
SendMsgImpl senSendMsgImpl = (SendMsgImpl) JdkProxyFactory.getProxy(new SendMsgImpl());
senSendMsgImpl.send("java");
// 保存动态生成的代理类源码
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
打印:
before method send
发送java
after method send
问:send怎么调用到了invoke上去了呢?
答:这里就得提一下,从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。Proxy.newProxyInstance方法生成了一个代理类$Proxy,这个代理类是动态生成的。查看这个$Proxy的源码,会看到:
public final void send() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
这个h就是:invocationhandler