代码之家  ›  专栏  ›  技术社区  ›  Nassim MOUALEK

对于泛型,lambda中的返回类型错误

  •  1
  • Nassim MOUALEK  · 技术社区  · 7 年前

    具有此泛型代码

    static final <T> List<Class<? extends T>> findSubClasses(Class<T> clz, String packageName){
        ClassPathScanningCandidateComponentProvider provider =
                    new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AssignableTypeFilter(clz));
        Set<BeanDefinition> beanDefinitions = provider.findCandidateComponents(packageName);
        List<Class<? extends T>> subClasses = beanDefinitions.stream().map(b->mapToClass(b, clz)).collect(Collectors.toList());
            return subClasses;
    }
    
    private static final <T> Class<? extends T> mapToClass(BeanDefinition beanDefinition, Class<T> clz) {
       String className = beanDefinition.getBeanClassName();
       try {
           return (Class<? extends T>) Class.forName(className);
       } catch (ClassNotFoundException e) {
           log.error("Failed to load the scanned class {}", className, e);
       }
       return null;
    }
    

    我在 b->mapToClass(b, clz)

    Bad return type in lambda expression: Class<capture of ? extends T> cannot be converted to Class<Object>
    

    如何修复此问题?

    2 回复  |  直到 7 年前
        1
  •  4
  •   Didier L    7 年前

    在这种情况下 编译器 map() 活动

    您只需提供新的流项目类型即可帮助实现这一点: Class<? extends T> 这样地:

    List<Class<? extends T>> subClasses = beanDefinitions.stream()
            .<Class<? extends T>>map(b-> mapToClass(b, clz))
            .collect(Collectors.toList());
    

    注意,这似乎只是IntelliJ中的一个bug,因为javac似乎很乐意编译它(如预期的那样)。

    作为侧节点,可以避免未选中的强制类型转换 mapToClass() 通过以下方式书写:

    return Class.forName(className).asSubclass(clz);
    
        2
  •  0
  •   Eugene    7 年前

    您为这些方法提供的一般信息是 非相关 ,即使你给他们取了相同的名字( T ). 如果您想使它们以某种方式相关,则需要在类级别声明它们。

    但在这种情况下,它不会起作用,因为您的方法是 static ; 因此,这将起作用,例如:

     public class YourClass<T> {
    
        final List<Class<? extends T>> findSubClasses(Class<T> clz, String packageName) {
            ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
            provider.addIncludeFilter(new AssignableTypeFilter(clz));
            Set<BeanDefinition> beanDefinitions = provider.findCandidateComponents(packageName);
            List<Class<? extends T>> subClasses = beanDefinitions.stream().map(b -> mapToClass(b, clz))
                    .collect(Collectors.toList());
            return subClasses;
        }
    
        private final Class<? extends T> mapToClass(BeanDefinition beanDefinition, Class<T> clz) {
            String className = beanDefinition.getBeanClassName();
            try {
                return (Class<? extends T>) Class.forName(className);
            } catch (ClassNotFoundException e) {
    
            }
            return null;
        }
    }
    

    编辑

    事实上 Didier's points out 这适用于 javac-8 javac-9 因此根本不需要进行任何重构。。。