使用泛型,我如何定义允许传入任何对象并且不提供警告的类?

时间:2013-06-17 17:31:06

标签: java generics

我有一个这样定义的界面:

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 to ... AdditionalProcessing

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


我试过这个:

public class NoAdditionalProcessing implements AdditionalProcessing<Object, Object>

但是这给了我一个错误,因为需要我传递了Object。我试过了

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

但那不会编译。

5 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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 >类型(即生成的类型)。 (嵌套泛型使它变得更加混乱。)I.e。对于ComapareTwoTypes<FIRST, SECOND>,您需要允许接受 超级类型的比较器

一些例子作为模式:

  • Validator<? super I, ? super O>

    仅在 super 类型上执行验证是可以接受的。它消耗这两种类型,用于比较,什么都不产生。

  • Converter<? super I, ? extends O>

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

要想出两个都是extends的例子要困难得多,因为如果没有额外的提示,Java编译器将无法可靠地推断出类型。这种情况主要发生在IO本身是泛型的情况下,例如由于收藏品的逆转,另一种类型的收藏品。

Wikipedia has an article on covariance and contravariance of types可能有助于对这里出现的情况有所启​​发(遗憾的是,这篇文章有点理论化)。但收藏是最明显的情况。我认为这是一些C ++有这个“一袋苹果不是一袋水果:你不允许在其中放一个香蕉”的例子,虽然主要的一个涉及putting submarines in a car parking lot(如果停车场)汽车是一种停车场的车辆;但它们不是。)

答案 2 :(得分:2)

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

public class NoAdditionalProcessing implements AdditionalProcessing<Object,Object> {

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

使用此代码,您上面的代码片段对我来说编译正常。警告免费。

答案 3 :(得分:2)

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

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

如果需要,您可以创建new NoAdditionalProcessing<Object, Object>

答案 4 :(得分:1)

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

摆脱警告

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