04. 反射和动态代理

3y 2021-08-19 11:14:07
Categories: Tags:

面试官今天要不来聊聊Java反射?你对Java反射了解多少?

候选者:嗯,Java反射在JavaSE基础中还是很重要的。

候选者:简单来说,反射就是Java可以给我们在运行时获取类的信息

候选者:在初学的时候可能看不懂、又或是学不太会反射,因为初学的时候往往给的例子都是用反射创建对象,用反射去获取对象上的方法/属性什么的,感觉没多大用

候选者:但毕竟我已经不是以前的我了,跟以前的看法就不一样了。

候选者:理解反射重点就在于理解什么是「运行时」,为什么我们要在「运行时」获取类的信息

候选者:在当时学注解的时候,我们可以发现注解的生命周期有三个枚举值(当时我还告诉过面试官你呢~)

候选者:分别是SOURCE、CLASS和RUNTIME,其实一样的,RUNTIME就是对标着运行时

候选者:我们都知道:我们在编译器写的代码是 .java 文件,经过javac 编译会变成 .class 文件,class 文件会被JVM装载运行(这里就是真正运行着我们所写的代码(虽然是被编译过的),也就所谓的运行时。

面试官:嗯,你说了那么多,就讲述了什么是运行时,还是快点进入重点吧

候选者:在运行时获取类的信息,其实就是为了让我们所写的代码更具有「通用性」和「灵活性」

候选者:要理解反射,需要抛开我们日常写的业务代码。以更高的维度或者说是抽象的思维去看待我们所写的“工具”

候选者:所谓的“工具”:在单个系统使用叫做“Utils”、被多个系统使用打成jar包叫做“组件”、组件继续发展壮大就叫做“框架”

候选者:一个好用的“工具”是需要兼容各种情况的。

候选者:你肯定是不知道用该“工具“的用户传入的是什么对象,但你需要帮他们得到需要的结果。

候选者:例如SpringMVC 你在方法上写上对象,传入的参数就会帮你封装到对象上

候选者:Mybatis可以让我们只写接口,不写实现类,就可以执行SQL

候选者:你在类上加上@Component注解,Spring就帮你创建对象

候选者:这些统统都有反射的身影:约定大于配置,配置大于硬编码。

候选者:通过”约定“使用姿势,使用反射在运行时获取相应的信息(毕竟作为一个”工具“是真的不知道你是怎么用的),实现代码功能的「通用性」和「灵活性」

面试官:嗯,明白了

面试官:结合之前说的泛型,想问下:你应该知道泛型是会擦除的,那为什么反射能获取到泛型的信息呢?

面试官:我再补充一下:泛型的信息只存在编译阶段,在class字节码就看不到泛型的信息了。那为什么下面这段代码能获取得到泛型的信息呢?

// 抽象类,定义泛型<T>
public abstract class BaseDao<T> {
    public BaseDao(){
        Class clazz = this.getClass();
        ParameterizedType  pt = (ParameterizedType) clazz.getGenericSuperclass(); 
        clazz = (Class) pt.getActualTypeArguments()[0];
        System.out.println(clazz);
    }
}

// 实现类
public class UserDao extends BaseDao<User> {
    public static void main(String[] args) {
        BaseDao<User> userDao = new UserDao();

    }
}
// 执行结果输出
class com.entity.User

候选者:嗯,这个问题我在学习的时候也想过

候选者:其实是这样的,可以理解为泛型擦除是有范围的,定义在类上的泛型信息是不会被擦除的。

候选者:Java 编译器仍在 class 文件以 Signature 属性的方式保留了泛型信息

候选者:Type作为顶级接口,Type下还有几种类型,比如TypeVariable、ParameterizedType、WildCardType、GenericArrayType、以及Class。通过这些接口我们就可以在运行时获取泛型相关的信息。

面试官:好,了解

面试官你了解动态代理吗?

候选者:嗯,了解的。动态代理其实就是代理模式的一种,代理模式是设计模式之一。

候选者:代理模型有静态代理和动态代理。静态代理需要自己写代理类,实现对应的接口,比较麻烦。

候选者:在Java中,动态代理常见的又有两种实现方式:JDK动态代理和CGLIB代理

候选者:JDK动态代理其实就是运用了反射的机制,而CGLIB代理则用的是利用ASM框架,通过修改其字节码生成子类来处理。

候选者:JDK动态代理会帮我们实现接口的方法,通过invokeHandler对所需要的方法进行增强。

候选者:动态代理这一技术在实际或者框架原理中是非常常见的

候选者:像上面所讲的Mybatis不用写实现类,只写接口就可以执行SQL,又或是SpringAOP 等等好用的技术,实际上用的就是动态代理。

面试官:嗯,了解了。

第一时间获取BATJTMD一线互联网大厂最新的面试资料以及内推机会关注公众号「对线面试官」