4

我有一个这样定义的接口:

public interface AdditionalProcessing<Pre, Post> {
    public void postProcess(Pre pre, Post post);
}

我已经决定要创建一个NoAdditionalProcessing扩展它的类。这是一个无操作,不会对其实施做任何事情。这是我的编译实现:

public class NoAdditionalProcessing implements AdditionalProcessing {

    @Override
    public void postProcess(Object o, Object o2) {

    }
}

问题是,当我将它传递给这样的方法签名时:

public <I, O> O map(I source, Class<O> destinationClass, AdditionalProcessing<I, O> additionalProcessing) throws MappingException 

它给了我一个关于方法调用的警告:

未经检查的分配: ...NoAdditionalProcessing 到 ...AdditionalProcessing

这些...是我排除的包名称。有没有办法摆脱这个警告?我基本上想定义NoAdditionalProcessing,所以它说,“我会接受任何东西,这无关紧要,没关系”。


我试过这个:

public class NoAdditionalProcessing implements AdditionalProcessing<Object, Object>

但这给了我一个错误,因为它要求我传入Object. 我试过了

public class NoAdditionalProcessing implements AdditionalProcessing<? extends Object, ? extends Object>

但这不编译。

4

5 回答 5

4

更改您的类声明以赋予类型参数值:

public class NoAdditionalProcessing 
    implements AdditionalProcessing<Object, Object>

然后,将您的方法签名更改为具有super通配符,以便您可以传入NoAdditionalProcessing任何目标类:

public <I, O> O map(I source, Class<O> destinationClass, 
    AdditionalProcessing<? super I, ? super O> additionalProcessing)
于 2013-06-17T17:41:59.497 回答
3

这是为什么我认为@RussellZahniser 解决方案优于@assylias 解决方案的长版本(但我还添加了另一个转折):

每当您使用泛型时,请考虑是否要允许子类型或超类型

虽然一开始可能看起来编译器过于迂腐,但泛型中的兼容性存在奇怪的反转。粗略地说:一袋苹果不是一袋水果。在一袋水果里,你可以放香蕉,但不能放在一袋苹果里。

因此,每当使用泛型时,请考虑是否要允许子类型(用于消费)或超类型(用于生产)。

假设你AdditionalProcessing应该是一个转换器,你可能实际上想把它写成AdditionalProcessing<IN, OUT>.

那么什么时候一个AdditionalProcessing与另一个兼容呢?

假设你需要一个类型的转换器AdditionalProcessing<Fruit, Fruit>。它必须接受任何一种水果,但它返回哪种水果也无关紧要。即它可以把苹果变成橙子。但是,它一定不能把苹果变成石头,因为那样你就不能喂橙子,也不能把水果拿出来。

所以对于转换器的情况,你的map函数实际上应该是这样的:

public <I, O> O map(I source, Class<O> destinationClass, 
    AdditionalProcessing<? super I, ? extends O> additionalProcessing)

自从:

? super I:“至少接受水果(但也可能接受其他东西!)”。

? extends O:“返回某种水果(但可能只有苹果)”。

我发现水果的例子真的很有价值。

NoAdditionalProcessing会看起来像这样:

public class NoAdditionalProcessing<TYPE>
  implements AdditionalProcessing<TYPE, TYPE> {
    @Override
    public void postProcess(Object o, Object o2) {
         // Actually I would have expected something like "return o1;"
    }
}

这本质上是我在第一行中提到的两个答案的融合。但是,很难从您的问题中判断您是否super想要extends. 这就是为什么我想强调两者都可能是合理的,你可能想要两者兼得。

通常,它将super用于输入类型(即消费数据)和extends输出类型(即生产类型)。(嵌套泛型会变得更加混乱。)即对于 a ComapareTwoTypes<FIRST, SECOND>,您将希望允许一个接受两个超类型的比较器。

一些作为模式的例子:

  • Validator<? super I, ? super O>

    如果它只对类型执行验证是可以接受的。为了比较,它消耗这两种类型,并且什么都不产生。

  • Converter<? super I, ? extends O>

    它可能选择接受超类型,并且可能将其返回值限制为某些超类型。它消耗第一种,生产第二种。

想出一个两者都是 的例子要困难得多extends,因为如果没有额外的提示,Java 编译器将无法可靠地推断出类型。这主要发生在它们本身是泛型时IO例如另一种类型的集合,因为集合的逆变性。

维基百科有一篇关于类型协变和逆变的文章,可能有助于阐明这里出现的情况(不幸的是,这篇文章有点理论化)。但集合是最明显的例子。我认为是一些 C++ 有这样的“一袋苹果不是一袋水果:你不能在里面放一根香蕉”的例子,尽管第一个例子涉及将潜艇放在停车场(如果停车场-lot-of-cars 是一种汽车停车场;但它们不是)。

于 2013-06-17T18:15:34.737 回答
2

您可以按如下方式声明您的类:

public class NoAdditionalProcessing<Pre, Post> 
                       implements AdditionalProcessing<Pre, Post> {
     @Override public void postProcess(Pre pre, Post post) { /*no-op*/ }
}

new NoAdditionalProcessing<Object, Object>然后,您可以根据需要创建一个。

于 2013-06-17T17:46:13.840 回答
2

你的NoAdditionalProcessing课不应该是这样的:

public class NoAdditionalProcessing implements AdditionalProcessing<Object,Object> {

    @Override
    public void postProcess(Object o, Object o2) {   }
}

使用此代码,您首先拥有的片段对我来说编译得很好。免费警告。

于 2013-06-17T17:41:17.213 回答
1

您可以通过添加注释来抑制警告来消除警告。

摆脱警告

@SuppressWarnings("unchecked")
public <I, O> O map(I source, Class<O> destinationClass, AdditionalProcessing<I, O> additionalProcessing) throws MappingException 
于 2013-06-17T17:39:36.243 回答