0

我有一个项目,其中服务接口使用@Service注释(自定义注释,而不是 Spring)进行注释,并且每个服务(hibernate、mongodb 等)可以有多个实现。

我正在尝试使用反射加载实现类,如下所示:

第一步:加载所有带@Service注解的接口

第 2 步:为每个接口加载所有子类

这是代码:

public static void main(String[] args) throws Exception{
    Reflections reflections = new Reflections("net.jitix.cfs");
    //load annotated interfaces
    Set<Class<?>> types=reflections.getTypesAnnotatedWith(Service.class);

    Iterator<Class<?>> typeIterator=types.iterator();

    typeIterator.forEachRemaining(new Consumer<Class<?>>() {

        @Override
        public void accept(Class<?> type) {
            if(!type.isInterface()){
                typeIterator.remove();
            }
        }
    });

    for(Class<?> type:types){
        //load implementation classes
        Set<Class<?>> implTypes=reflections.getSubTypesOf(type); //error here
    }

    //rest of the code
}

我得到的编译错误:Type mismatch: cannot convert from Set<Class<? extends capture#8-of ?>> to Set<Class<?>>

根据我的理解 Class<?>,表示类型可以是任何东西,所以我很困惑为什么需要的方法Class<T>不能Class<?>作为参数。

谁能帮我理解为什么会这样?我的方法有什么可能的替代方案吗?提前致谢!

编辑:根据@MGorgon 的评论以及@StriplingWarrior 和@Sotirios Delimanolis 使用反射方法的回答是毫无疑问的。有什么方法可以获取引用类型为类型的类型的子类型Class<?>

4

2 回答 2

2

这个问题的症结与反射无关,而是协变/逆变。它是有效的:

为什么我不能将 a 分配Set<? extends Something>给 a Set<?>

答案是,如果你有一个,Set<?>那么编译器会让你将任何类型的对象(比如X)添加到该集合中,并且有人试图从原来的值中检索该值Set<? extends Something>会得到一个运行时错误。X 不延长 Something

原理可以更简单地展示如下:

Set<Dog> dogs = getDogs();
Set<Pet> pets = dogs;        // the compiler will complain here
pets.add(new Cat("Fluffy")); // to avoid letting this happen
for(Dog dog : dogs)         // which would cause an exception here
{
   ...
}

但是,由于您(大概)知道您不打算向该集合中添加任何内容,因此通过一些显式转换告诉编译器您知道自己在做什么可能是安全的:

Set<Class<?>> implTypes= (Set<Class<?>>)(Set<?>)reflections.getSubTypesOf(type);
于 2014-08-26T22:13:59.560 回答
1

getSubTypesOf方法声明为

public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {

它是一个泛型方法,声明T为类型参数。当您调用该方法时,该方法调用会捕获一个类型参数,无论是隐式还是因为它是显式提供的。

您已经使用 type 的参数调用了该方法Class<?>。该方法将捕获?as 类型。因此,方法返回类型将变为Set<Class<? extends CAP of ?>>,即。一组未知类型的类,它们是特定未知类型的子类型。

但是,您正试图将其分配给Set<Class<?>>一组未知类型的类。但那个未知类型不一定是某个特定未知类型的子类型。我知道当你大声说出来时这没有多大意义,但考虑?CAP of ?作为一种特定类型。这与尝试做的相同

Set<Class<?>> implTypes = new HashSet<Class<Integer>>();

这不是很明显,因为Classisfinal并且因此不能被子类化,但是 aHashSet<Class<Integer>>不能以Set<Class<?>>与 a 不能分配给 a 相同的方式ArrayList<ArrayList<Integer>分配给 a List<List<?>>

补充阅读:

于 2014-08-26T22:21:32.290 回答