MST

星途 面试题库

面试题:Java 基础类、泛型与反射的深度结合应用

创建一个泛型类 `ReflectionGenericClass<T>`,该类有一个构造函数接收一个 `T` 类型的对象。要求实现一个方法 `invokeMethodByName`,这个方法接收一个字符串(方法名)和一个 `Object` 数组(方法参数),通过反射机制调用传入对象(`T` 类型实例)的指定方法,并返回结果。假设 `T` 是 `java.lang.Number` 的子类。请写出完整的代码实现,并详细阐述在这个过程中泛型、反射以及 `Number` 类的特性是如何协同工作的,同时分析这种实现可能存在的潜在风险。
49.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

代码实现

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionGenericClass<T extends Number> {
    private T instance;

    public ReflectionGenericClass(T instance) {
        this.instance = instance;
    }

    public Object invokeMethodByName(String methodName, Object[] params) {
        try {
            // 获取T类型的Class对象
            Class<? extends Number> clazz = instance.getClass();
            // 根据方法名和参数类型获取Method对象
            Method method = null;
            if (params == null || params.length == 0) {
                method = clazz.getMethod(methodName);
            } else {
                Class<?>[] paramTypes = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    paramTypes[i] = params[i].getClass();
                }
                method = clazz.getMethod(methodName, paramTypes);
            }
            // 调用方法并返回结果
            return method.invoke(instance, params);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }
    }
}

泛型、反射以及Number类特性的协同工作

  1. 泛型:通过定义 ReflectionGenericClass<T extends Number>,确保了传入的类型 T 必须是 Number 类或其子类,这使得代码具有类型安全性,在编译期就能检查类型错误,并且代码可以复用。同时限定 TNumber 的子类,使得后续反射操作针对的是具有 Number 特性的类。
  2. 反射invokeMethodByName 方法中使用反射机制。通过 instance.getClass() 获取 T 类型的 Class 对象,这是反射操作的入口。然后根据方法名和参数类型获取 Method 对象,进而使用 method.invoke 调用实例的指定方法。反射机制使得代码可以在运行时动态调用方法,提高了代码的灵活性。
  3. Number类特性:由于 TNumber 的子类,这意味着 T 类型的实例具有 Number 类定义的方法,例如 intValue()doubleValue() 等。在反射调用方法时,就可以调用这些 Number 类提供的通用方法,增加了代码的通用性和可预测性。

潜在风险

  1. 性能问题:反射操作相对直接调用方法性能较低。因为反射需要在运行时解析方法名、参数类型等信息,涉及到动态查找和类型检查,这比编译期绑定的直接方法调用要慢很多。在性能敏感的场景下,频繁使用反射可能会导致性能瓶颈。
  2. 安全性问题:反射可以访问类的私有方法和字段,如果使用不当,可能会破坏类的封装性,导致程序出现不可预测的行为。例如,在上述代码中,如果传入的 methodName 是一个私有方法名,且程序逻辑依赖于类的封装性,就可能引发问题。
  3. 类型兼容性问题:虽然泛型确保了 TNumber 的子类,但在反射调用时,Object[] params 数组中的参数类型需要与目标方法参数类型严格匹配。如果参数类型不匹配,在运行时会抛出 IllegalArgumentException。此外,如果 T 类型的子类重写了 Number 类的方法并改变了参数类型,也可能导致反射调用失败。
  4. NoSuchMethodException:如果传入的 methodName 不存在于 T 类型的实例中,会抛出 NoSuchMethodException。在实际应用中,需要对这种异常进行适当处理,以避免程序崩溃。
  5. IllegalAccessException:如果目标方法是私有的,并且没有合适的访问权限(例如未设置 setAccessible(true)),会抛出 IllegalAccessException。这也提醒开发者在使用反射时要谨慎处理访问权限问题。