Java 实体组件系统 - 推理变量 T 具有不兼容的边界

Java Entity Component System - Inference variable T has incompatible bounds

我正在尝试在 java 中制作自定义实体组件系统,但我在类型擦除方面遇到了一些困难。整个系统功能正常保存一个方法。我希望能够调用一个通用方法 createEntity(Class<? extends Component>... types);,它接收一个 var args 类型数组,创建一个新的空白实体,并使用反射添加指定类型的新组件。这是我写的方法。

public Entity createEntity(Class<? extends Component>... types){
    Entity e = new Entity();  
    for(Class<? extends Component> type: types){
        try {
            getParent().getComponentManager().add(type, e.UID, type.newInstance());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }              
    INDEX.add(e.UID, e);
    return e;
}  

这是造成编译错误的行。

getParent().getComponentManager().add(type, e.UID, type.newInstance());

这是ComponentManager里面的方法class.

public <T extends Component> void add(Class<T> type, int uid, T component){
    if(component != null){
        ComponentIndex<T> index = getComponentsByType(type);
        if(!index.has(uid)){
            index.add(uid, component);
            component.setParent(this);
        }
    }        
}

Component class只是一个空接口。

public interface Component{}

我不断从 NetBeans 工具提示中得到的错误类似于

...method add in class ComponentManager cannot be applied to given types; required: Class, int, T found: Class, int, Class reason: inference variable T has incompatible bounds...

鉴于所有组件都将实现 Component 接口,并且所有组件都将具有不带参数的构造函数,我如何使用反射创建基于泛型 Class<?> 的组件?

因此,我在阅读本文后找到了解决此特定问题的方法。 https://docs.oracle.com/javase/tutorial/java/generics/capture.html

问题在于,当使用通配符时,编译器无法保证对象的类型正确,但通过使用通用辅助方法,您可以通过捕获通配符的类型来确保每个元素的类型安全。在这种情况下,这是我使用的辅助方法。

private <T extends Component> void addNewComponentInstance(Class<T> type, int uid){
    try {
        getParent().getComponentManager().add(type, uid, type.newInstance());
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

这就是它被夹在通配符方法中的方式。

public Entity createEntity(Class<? extends Component>... types){
    Entity e = new Entity();  
    for(Class<? extends Component> type: types)
        addNewComponentInstance(type, e.UID);                   
    INDEX.add(e.UID, e);
    return e;
}

此解决方案可以正确编译和运行。