如何优化Java方法使其返回Map<Class<? super C>, A>类型注解结果
解决方案:优化方法签名以返回
Map<Class<? super C>, A> 首先明确:你对返回类型的逻辑判断是完全正确的——遍历过程中收集到的所有类(当前类、父类、实现的接口及其父接口)都是C的泛型超类型,即Class<? super C>,因此可以安全地将结果转换为这个类型。
下面提供两种合理的实现方案,避免硬hack的同时满足类型约束:
方案1:保持核心方法不变,仅修改便捷方法
核心方法继续使用Map<Class<?>, A>作为累加器(兼容递归时的任意超类型),在便捷方法中基于业务逻辑进行安全的类型转换:
修改后的代码
import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Objects; // 核心方法保持原有逻辑,仅泛型参数适配 private static <A extends Annotation> Map<Class<?>, A> getAnnotationsByClassAnnotatedWith( Class<?> clazz, Class<A> annotationClass, Map<Class<?>, A> annotationsByClass, Set<Class<?>> encounteredClasses) { Class<?> nonNullClazz = Objects.requireNonNull(clazz); if (!encounteredClasses.contains(nonNullClazz)) { encounteredClasses.add(nonNullClazz); A classAnnotation = nonNullClazz.getAnnotation(annotationClass); if (classAnnotation != null) { annotationsByClass.put(nonNullClazz, classAnnotation); } // 遍历所有实现的接口 for (Class<?> classInterface : nonNullClazz.getInterfaces()) { getAnnotationsByClassAnnotatedWith(classInterface, annotationClass, annotationsByClass, encounteredClasses); } // 遍历父类 final Class<?> superClass = nonNullClazz.getSuperclass(); if (superClass != null) { getAnnotationsByClassAnnotatedWith(superClass, annotationClass, annotationsByClass, encounteredClasses); } } return annotationsByClass; } // 便捷方法修改签名并添加安全转换 @SuppressWarnings({"unchecked", "rawtypes"}) public static <C, A extends Annotation> Map<Class<? super C>, A> getAnnotationsByClassAnnotatedWith( Class<C> clazz, Class<A> annotationClass) { // 基于业务逻辑,所有收集到的Class都是C的超类型,转换安全 return (Map) getAnnotationsByClassAnnotatedWith( clazz, annotationClass, new HashMap<>(), new HashSet<>()); }
方案说明
- 核心方法无需修改,递归调用时可以自由处理任意类型的超类/接口;
- 便捷方法的类型转换是安全的:因为我们的遍历逻辑严格限制在
C的继承/接口层级内,所有Map的键必然是C的超类型; - 使用
@SuppressWarnings抑制警告是合理的,因为编译器无法理解业务逻辑的约束,但我们可以保证转换的安全性。
方案2:修改核心方法泛型,适配超类型递归
让核心方法的泛型直接支持? super C,递归时显式转换超类/接口的类型:
修改后的代码
import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Objects; private static <C, A extends Annotation> Map<Class<? super C>, A> getAnnotationsByClassAnnotatedWith( Class<C> clazz, Class<A> annotationClass, Map<Class<? super C>, A> annotationsByClass, Set<Class<?>> encounteredClasses) { Class<C> nonNullClazz = Objects.requireNonNull(clazz); if (!encounteredClasses.contains(nonNullClazz)) { encounteredClasses.add(nonNullClazz); A classAnnotation = nonNullClazz.getAnnotation(annotationClass); if (classAnnotation != null) { annotationsByClass.put(nonNullClazz, classAnnotation); } // 遍历接口:接口是C的超类型,安全转换 for (Class<?> iface : nonNullClazz.getInterfaces()) { getAnnotationsByClassAnnotatedWith((Class<? super C>) iface, annotationClass, annotationsByClass, encounteredClasses); } // 遍历父类:父类是C的超类型,安全转换 final Class<?> superClass = nonNullClazz.getSuperclass(); if (superClass != null) { getAnnotationsByClassAnnotatedWith((Class<? super C>) superClass, annotationClass, annotationsByClass, encounteredClasses); } } return annotationsByClass; } @SuppressWarnings("unchecked") public static <C, A extends Annotation> Map<Class<? super C>, A> getAnnotationsByClassAnnotatedWith( Class<C> clazz, Class<A> annotationClass) { return getAnnotationsByClassAnnotatedWith(clazz, annotationClass, new HashMap<>(), new HashSet<>()); }
方案说明
- 核心方法的签名直接体现了返回值的类型约束;
- 递归时的类型转换同样是安全的,因为接口和父类必然是
C的超类型; - 仅需在递归调用处添加一次类型转换,整体代码的类型语义更清晰。
内容的提问来源于stack exchange,提问作者Garret Wilson
相关产品推荐
相关产品推荐

