【问题标题】:Java Generic classes assignability [duplicate]Java泛型类可分配性[重复]
【发布时间】:2013-08-16 22:06:26
【问题描述】:

我有以下课程:

    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 实现它。

【问题讨论】:

  • 这是发生在 Eclipse 中还是 JDK 中? Eclipse 编译器包含一些错误。
  • @dsmog 正确的术语是“泛型”(Java)、“模板类”(C++ 中一个语法相似但概念上非常不同的概念)。

标签: java generics


【解决方案1】:

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

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&lt;Wrap&lt;ConcreteModel&gt;&gt; is not a SomeGeneric&lt;Wrap&lt;? extends ModelObject&gt;&gt;

【讨论】:

    【解决方案2】:

    Wrap&lt;ConcreteModel&gt;Wrap&lt;? extends ModelObject&gt; 的子类型?是的。

    Transformer&lt;Resource, Wrap&lt;ConcreteModel&gt;&gt;Transformer&lt;Resource, Wrap&lt;? extends ModelObject&gt;&gt; 的子类型?没有。

    同理:

    StringObject 的子类型?是的。

    List&lt;String&gt;List&lt;Object&gt; 的子类型?没有。

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

    你可能想要的是

    Transformer&lt;Resource, ? extends Wrap&lt;? extends ModelObject&gt;&gt;

    【讨论】:

      【解决方案3】:

      Wrap&lt;ConcreteModel&gt; 可以分配给Wrap&lt;? extends ModelObject&gt; 类型的变量。但是这里的问题比较复杂。

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

      另一方面,拥有ArrayList&lt;Wrap&lt;ConcreteModel&gt;&gt; list 意味着您只能向其中添加Wrap&lt;ConcreteModel&gt;s,而不能向其中添加Wrap&lt;ModelObject&gt;,因为列表只能包含包装的ConcreteModels,以及包裹的ModelObject 不是包裹的ConcreteModel,也不能被转换为一个。

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

      编译器需要强制执行这一点,因为Transformer&lt;F, T&gt; 可以声明一个方法:

      void myMethod(F fObject, T tObject);
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 2011-08-17
        • 1970-01-01
        • 2017-11-06
        • 2014-06-12
        • 2018-06-12
        • 2012-04-03
        相关资源
        最近更新 更多