【面经总结】Java基础 - 反射

22 阅读3分钟

反射

什么是反射

运⾏时获得类的信息,创建类的对象,调⽤其中的⽅法和属性。

反射的作用

  1. 动态代理
  2. 框架的实现(Spring、Spring Boot、MyBatis)
  3. 注解
  4. 提高了代码灵活性

获取 Class 类对象的 4 种方法

// 已知类
// 通过此方式获取 Class 对象不会进行初始化
Class userClass = User.class;

// 对象
// User user = new User();
Class userClass = user.getClass();

// 类的全路径
Class userClass = Class.forName("cn.wmhwiki.User")


// 类加载器
// 通过此方式获取 Class 对象不会进行初始化
Class userClass = ClassLoader.getSystemClassLoader().loadClass("cn.wmhwiki.User");

动态代理

静态代理实现

  1. 定义接口
public interface Animal {
    void makeSound();
}
  1. 实现接口
public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}
  1. 创建代理类
public class AnimalProxy implements Animal {
    private Animal animal;

    public AnimalProxy(Animal animal) {
        this.animal = animal;
    }

    @Override
    public void makeSound() {
        System.out.println("Before making sound...");
        animal.makeSound();
        System.out.println("After making sound...");
    }
}
  1. 使用代理类
public class StaticProxyDemo {
    public static void main(String[] args) {
        AnimalProxy animalProxy = new AnimalProxy(new Dog());
        animalProxy.makeSound();
    }
}

JDK 动态代理实现

  1. 创建接口,创建原始类实现接口

  2. 创建动态代理处理器,实现 InvocationHandler 接口,重写 invoke() 方法

  3. 创建原始对象和动态代理处理器对象。

  4. 使用 Proxy.newProxyInstance() 方法将使用代理对象和动态代理处理器对象创建代理对象。

  5. 定义接口

public interface Animal {
    void makeSound();
}
  1. 实现接口
public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}
  1. 创建动态代理处理器,实现 InvocationHandler 接口
public class AnimalInvocationHandler implements InvocationHandler {
    private Object target;

    public AnimalInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before making sound...");
        Object result = method.invoke(target, args);
        System.out.println("After making sound...");
        return result;
    }
}
  1. 创建并使用代理类
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        AnimalInvocationHandler handler = new AnimalInvocationHandler(dog);

        Animal proxy = (Animal) Proxy.newProxyInstance(
                // 原始类的 ClassLoader 对
                象
                Animal.class.getClassLoader(),
                // 原始对象所实行的接口
                dog.getClass().getInterfaces(),
                // 关联代理对象
                handler
        );

        proxy.makeSound();
    }
}

CGLIB 动态代理实现

  1. 创建原始类

  2. 创建方法拦截器,并实现 MethodInterceptor 接口

  3. 使用 Enhancer 类来设置被代理类和回调方法拦截器,创建代理对象

  4. 创建原始类

public class Dog {
    public void makeSound() {
        System.out.println("Woof!");
    }
}
  1. 创建方法拦截器,并实现 MethodInterceptor 接口
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method execution");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method execution");
        return result;
    }
}
  1. 创建 Enhancer 对象并配置,并创建代理对象。
public class Main {
    public static void main(String[] args) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        // 设置原始类
        enhancer.setSuperclass(Dog.class);
        // 设置回调方法拦截器为 MyMethodInterceptor
        enhancer.setCallback(new MyMethodInterceptor());

        // 创建代理对象
        Dog proxy = (Dog) enhancer.create();

        // 调用代理对象的方法
        proxy.makeSound();
    }
}

JDK 动态代理和 CGLIB 动态代理的差异?

  1. 实现⽅式
    1. JDK:反射
    2. CGLIB:继承⽬标类
  2. ⽬标类限制
    1. JDK:⽬标类必须要实现接⼝
    2. CGLIB:没有限制。
  3. 性能:JDK 动态代理相对于 CGLIB 动态代理较低
  4. 对象类型:
    1. JDK:只能代理实现了接⼝的类
    2. CGLIB:通过继承实现,不能代理 final 类
  5. 依赖库:
    1. JDK: Java ⾃带的库,不需要额外的依赖
    2. CGLIB :依赖 cglib 库