【问题标题】:Generics in Java, returning a set of a generic class Set<T>Java 中的泛型,返回一组泛型类 Set<T>
【发布时间】:2018-11-28 09:21:17
【问题描述】:

所以我有这段代码,我试图返回一组扩展另一个类的类

public static <T> Set<T> getClassesExtending(Class<T> clazz) {
    Reflections reflections = new Reflections("");
    Set<Class<? extends T>> classes = reflections.getSubTypesOf(clazz);

    if (classes.size() <= 0) return new HashSet<>();

    Set<T> extending = classes.stream().filter(c -> c instanceof T).collect(Collectors.toSet());

    return extending;
}

问题:

c instanceof T //shows compile error 'Class or array expected' above 'T'

例如,如果我要写...

getClassesExtending(MyClass.class).forEach(c -> c.methodInMyClass())

它会起作用的。有什么建议吗?

【问题讨论】:

  • 只要使用filter(clazz::isInstance)
  • 如何从Stream&lt;Class&lt;? extends T&gt;&gt; 获得Set&lt;T&gt;
  • 试过 filter(clazz::isInstance) 但它显示此错误“不兼容的类型。必需的 Set 但 'collect' 被推断为 R:不存在类型变量的实例,因此 Class extends T> 符合 T 推理变量 T 具有不兼容的界限:等式约束:T 下界:Class extends T>"
  • filter(c -&gt; c instanceof T) 中,参数c 的类型为Class&lt;? extends T&gt;,因此永远不可能是instanceof T,因为Class 类不是从T 派生的。
  • getSubTypesOf 方法返回类 java.lang.Class 的实例,这与您正在寻找的类的实例完全不同。您没有任何A 的实例,您只有Class&lt;A&gt; 的实例,并且这些实例与A 类无关。

标签: java class generics


【解决方案1】:
  • 首先,从您所描述的使用方式来看,您希望
    • 查找扩展类clazz的类
    • 使用默认构造函数创建对象,然后
    • 对它们调用方法。

这段代码应该可以完成你的工作

public static <T> Set<? extends T> getClassesExtending(Class<T> clazz) {
        Reflections reflections = new Reflections("");
        Set<Class<? extends T>> classes = reflections.getSubTypesOf(clazz);

        if (classes.size() <= 0) return new HashSet<>();

        Set<? extends T> extending =
                classes.stream().map(aClass -> {
                    try {
                        return aClass.getConstructor().newInstance();
                    } catch (Exception e) {
                        return null;
                    }
                }).collect(Collectors.toSet());
         return extending;
    }    

我建议您在extending 集合中加入filter() 操作以过滤掉任何没有无参数构造函数的子类,以防止nulls 出现。

  • 其次,当你这样做

    Set&lt;T&gt; extending = classes.stream().filter(c -&gt; c instanceof T).collect(Collectors.toSet());

如果您实际上是在尝试将集合过滤到类中,则该操作将是幂等的,也就是说它不会对集合产生任何变化。

最后,c instanceof T 导致编译错误的原因是因为instanceOf 运算符不允许在其 rhs 上使用 non-refiable 类型,而泛型类型是 non-refiable。 (JLS 11 section: 15.20.2)

【讨论】:

    【解决方案2】:

    这里的问题是T 在运行时被擦除。

    你可以试试这个:

    Set<T> extending = classes.stream().filter(c -> c.isAssignableFrom(clazz)).collect(Collectors.toSet());
    

    【讨论】:

    • c 已经是 Class。所以c.getClass() 会返回java.lang.Class.class
    • @Realmm 解决了这个问题,也解决了 DodgyCodeException 提到的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    • 2021-06-28
    • 2021-12-25
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    相关资源
    最近更新 更多