我在泛型和继承方面有些纠结。总体思路是针对各种组件以及包含其他组件的组或容器组件的构建器模式。有些组件组需要特定组件,有些可以是任何组件。这就是问题所在。我认为最好用代码解释:

public abstract class AbstractGroupComponentBuilder <T extends ComponentGroup<R>, R extends AbstractDashboardComponent> implements ComponentBuilder<ComponentGroup<R>> {
    private List<ComponentBuilder<R>> children;
    protected void child(ComponentBuilder<R> builder){
        children.add(builder);
    }
...
}

public  class ComponentGroupBuilder extends AbstractGroupComponentBuilder<ComponentGroup<AbstractDashboardComponent>, AbstractDashboardComponent>{

    public <T> TableBuilder<T> table(Class<T> clazz){
        TableBuilder<T> builder = new TableBuilder<T>(clazz);
        child(builder);  // PROBLEM HERE: The method child(ComponentBuilder<AbstractDashboardComponent>) in the type AbstractGroupComponentBuilder<ComponentGroup<AbstractDashboardComponent>,AbstractDashboardComponent> is not applicable for the arguments (TableBuilder<T>)

    }
    ...
}

public class TableBuilder<T> implements ComponentBuilder<Table> {
...
}

public class Table extends AbstractDashboardComponent{
...
}

public class ComponentGroup<T extends AbstractDashboardComponent> extends AbstractDashboardComponent {
...
}

public interface ComponentBuilder<T extends AbstractDashboardComponent> {
    public T build();
}


所以编译器的错误是:"The method child(ComponentBuilder<AbstractDashboardComponent>) in the type AbstractGroupComponentBuilder<ComponentGroup<AbstractDashboardComponent>,AbstractDashboardComponent> is not applicable for the arguments (TableBuilder<T>)"
由于TableBuilder<T> extends ComponentBuilder<Table>和“表扩展了AbstractDashboardComponent”,所以为什么不兼容。

最佳答案

在这里,您的构建器的类型为TableBuilder<Table>。这与ComponentBuilder<AbstractDashboardComponent>不兼容。问题不是ComponentBuilder,它是<>中的内容。与普通类型不同,侧面<>中的内容是不变的,这意味着类型必须完全匹配,不允许使用子类型。

原因如下:我将使用非常简单和熟悉的类型进行解释:

List<Integer> ints = new ArrayList<Integer>();
List<Number> numbers = ints; // PROBLEM LINE
numbers.add(5.0);
ints.get(0); // uhoh - that's a double and not an int!


标记为PROBLEM的行?那不会编译。解决方法是这样的:

List<Integer> ints = new ArrayList<Integer>();
List<? extends Number> numbers = ints; // this is fine
numbers.add(5.0); // PROBLEM LINE
ints.get(0); // uhoh - that's a double and not an int!


在此示例中,错误在第三行:您不能在List<? extends NothingYouTypeHereCanFixThat>中添加任何内容(不相关的详细信息:文字null除外)。

这就是为什么第二行现在很好的原因。

您需要做同样的事情,并在编译前添加一些? extends

<T> =不变量;只有精确的T可以计算出来,但是您可以以各种方式使用T。

<? extends T> =协变T或T的任何子类型都可以,但是您只能调用get样式方法。

<? super T> =反变数; T或T的任何SUPERTYPE都可以,但是您只能调用添加样式的方法(可以调用get,但是只获取Object)。

矛盾很少出现。它可以让您执行以下操作:

List<? super Integer> list = ...;
list.add(5); // compiles fine.
Object o = list.get(0); // all you get is `Object` here.


如果您有List<Number>,则可以将其分配给list变量。

07-27 13:35