Java通用类可分配性

时间:2013-08-16 22:06:26

标签: java generics

我有以下课程:

    public interface ModelObject {
    }
    public interface Resource {
    }
    public interface Transformer <F,T>{
    }
    public interface WrapperFactory {
        Transformer<Resource, Wrap<? extends ModelObject>> createMapper();
    }
    public class Wrap<E extends ModelObject> {

    }

    public class AbstractBaseTransformer<F,T> implements Transformer<F,T> {
    }
    public class ConcreteModel implements ModelObject {

    }
    public class ConcreteTransformer extends AbstractBaseTransformer<Resource, Wrap<ConcreteModel>> {

    }
    public class ConcreteFactory implements WrapperFactory {

        @Override
        public Transformer<Resource, Wrap<? extends ModelObject>> createMapper() {
            return new ConcreteTransformer();
        }
    }

ConcreteFactory没有编译声明ConcreteTransformer与返回的

不兼容
Transformer<Resource, Wrap<? extends ModelObject>>

我看不出这里有什么问题。 ConcreteTransformer将第一个参数绑定到Resource(与预期相同),同时将第二个参数绑定到:

Wrap<ConcreteModel>

应绑定到:

Wrap<? extends ModelObject> 

当ConcreteModel实现它。

3 个答案:

答案 0 :(得分:4)

这是一个更简单的版本,以缩小问题范围:

interface ModelObject {}
class ConcreteModel implements ModelObject {}

class Wrap<E extends ModelObject> {}
class SomeGeneric<T> {}

class Simple {
    public SomeGeneric<Wrap<? extends ModelObject>> m() {
        return new SomeGeneric<Wrap<ConcreteModel>>();
    }
}

也不编译。

您的问题是SomeGeneric<Wrap<ConcreteModel>> is not a SomeGeneric<Wrap<? extends ModelObject>>

答案 1 :(得分:1)

Wrap<ConcreteModel>Wrap<? extends ModelObject>的子类型?是。

Transformer<Resource, Wrap<ConcreteModel>>Transformer<Resource, Wrap<? extends ModelObject>>的子类型?否。

它与:

相同

StringObject的子类型?是。

List<String>List<Object>的子类型?否。

基本上,要使参数化类型兼容,如果顶级参数不是通配符,则参数必须与完全匹配。在您的情况下,顶级参数不是通配符,并且参数不完全匹配。

你可能想要的是

Transformer<Resource, ? extends Wrap<? extends ModelObject>>

答案 2 :(得分:0)

可以将Wrap<ConcreteModel>分配给Wrap<? extends ModelObject>类型的变量。但这里的问题更复杂。

假设您有ArrayList<Wrap<? extends ModelObject>> list。当您有这样的类型时,这意味着您可以在列表中添加Wrap<ConcreteModel>,但这也意味着您可以向其添加Wrap<ModelObject>。简而言之,这意味着您有一个列表,其中可以包含任何可以转换为ModelObject的Wrap。

另一方面,拥有ArrayList<Wrap<ConcreteModel>> list意味着您只能添加Wrap<ConcreteModel>,而Wrap<ModelObject>无法添加到其中,因为该列表只能包含ConcreteModel {1}} s,被包裹的ModelObject不是被包裹的ConcreteModel,也不能被归为一个。

这正是你的情况。您声明了createMapper()方法返回Transformer<Resource, Wrap<? extends ModelObject>>。这意味着返回的Transformer的第二个参数必须能够是ModelObject的任何子类,包括ModelObject本身。相反,您正在尝试返回Transformer<Resource, Wrap<ConcreteModel>>

编译器需要强制执行此操作,因为Transformer<F, T>可以声明一个方法:

void myMethod(F fObject, T tObject);

如果是这种情况,类型为myMethod的对象的方法Transformer<Resource, Wrap<? extends ModelObject>>将接受类型为ModelObject的对象作为其第二个参数。另一方面,类型为Transformer<Resource, Wrap<ConcreteModel>> 的对象中的同一方法不能接受ModelObject作为其第二个参数。