我有一个这样定义的界面:
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>
但那不会编译。
答案 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编译器将无法可靠地推断出类型。这种情况主要发生在I
和O
本身是泛型的情况下,例如由于收藏品的逆转,另一种类型的收藏品。
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