首页 > 解决方案 > 无法理解泛型和继承

问题描述

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

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>和'Table extends AbstractDashboardComponent'。

标签: javagenericsinheritance

解决方案


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

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

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!

在此示例中,错误出现在第三行:您不能将ANYTHING添加到List<? extends NothingYouTypeHereCanFixThat>(不相关的详细信息:除了文字null)。

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

你需要做同样的事情并扔一些东西? extends直到它编译。

<T>= 不变的;只有精确的 T 可以解决,但您可以以任何您想要的方式使用 T。

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

<? super T>=逆变;T 或 T 的任何 SUPERTYPE 都可以,但你只能调用 add 样式的方法(你可以调用 get,但你只会得到 Object)。

逆变很少出现。它让您可以:

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

如果你有一个List<Number>,你可以将它分配给列表变量。


推荐阅读