考虑以下接口和类:
interface BaseInterface { }
interface DerivedInterface extends BaseInterface { }
class BaseClass
{
void baseFunc1( BaseInterface foo ) { }
void baseFunc2( Collection<BaseInterface> foo ) { }
void baseFunc3( Collection<? super DerivedInterface> foo ) { }
}
class DerivedClass extends BaseClass
{
void derivedFunc1( DerivedInterface foo )
{
baseFunc1( foo ); //no problem here.
}
void derivedFunc2( Collection<DerivedInterface> foo )
{
baseFunc2( foo ); //error!
}
void derivedFunc3( Collection<DerivedInterface> foo )
{
baseFunc3( foo ); //fixed it, but the fix is unreasonable.
}
}
当
derivedFunc1()
调用baseFunc1()
时没有问题,因为可以从DerivedInterface
分配BaseInterface
。但是,当
derivedFunc2()
调用baseFunc2()
时,会出现问题,因为显然无法从Collection<DerivedInterface>
分配Collection<BaseInterface>
。考虑到我对Java的协方差和相反性的理解(绝对不清楚),我能想到的解决此问题的唯一方法是将
baseFunc3()
声明为接受Collection<? super DerivedInterface>
,该值可从Collection<DerivedInterface>
赋值。当然,这是不合理的,因为
BaseClass
的设计不能理会某些DerivedInterface
的知识,更不用说对BaseInterface
的派生链设置上限了。在我编写的这种代码中,这是一个经常发生的问题,每当我遇到它时,当前处理它的方式就是向运行时添加转换逻辑。
我的问题:是否有任何简便的方法让
derivedFunc2
将其Collection<DerivedInterface>
传递给baseFunc2
而不对BaseClass
进行任何不合理的更改(例如添加baseFunc3()
),并且不花费运行时转换的费用?编辑:
我正在使用的界面实际上不是
Collection
界面,(当然,由于可能有人会添加DerivedInterface
的集合,因此我当然不希望将BaseInterface
的集合视为BaseInterface
的集合。到该集合中,该对象实现了DerivedInterface
而不是Predicate
。)我正在使用
BaseInterface
接口,该接口包含一个接受BaseInterface
作为参数的方法。实现该接口的对象永远不需要存储传递给它们的BaseInterface
实例,它们只需要调用该BaseInterface
的某些方法,但是正如Thomas所指出的,这没有什么区别。因此,由于必须将
baseFunc2
传递给Predicate.evaluate()方法,因此声明<? extends BaseInterface>
接受将不起作用。 最佳答案
BaseClass.baseFunc2
应该接受Collection< ? extends BaseInterface >
作为其参数。在Java中,泛型实例的协变或协变是在其使用时声明的,而不是在类定义本身处声明的。
为什么T
不属于您设计中的类层次结构?
class BaseClass< T > {
void baseFunc1( T foo ) { }
void baseFunc2( Collection< ? extends T > foo ) {
// use foo in covariant fashion,
// e.g., foo.contains( t )
// can accept Collection< T >, Collection< S > (where S <: T)
}
void baseFunc3( Collection< ? super T > foo ) {
// use foo in contravariant fashion,
// e.g., foo.add( t )
// can accept Collection< T >, Collection< S > (where S >: T)
}
void baseFunc4( Collection< T > foo ) {
// use foo in invariant fashion,
// e.g., foo.add( foo.iterator().next() )
// can only accept Collection< T >
}
}
现在你可以做
class DerivedClass extends BaseClass< DerivedInterface > {
void derivedFunc1( DerivedInterface foo ) {
baseFunc1( foo );
}
void derivedFunc2( Collection< DerivedInterface > foo ) {
baseFunc2( foo );
}
void derivedFunc3( Collection< DerivedInterface > foo ) {
baseFunc3( foo );
}
}
如果您不能在
T
中使用BaseClass
,则只能class DerivedClass extends BaseClass {
void derivedFunc1( DerivedInterface foo ) {
baseFunc1( foo );
}
void derivedFunc2( Collection< DerivedInterface > foo ) {
baseFunc2( foo );
}
void derivedFunc3( Collection< BaseInterface > foo ) {
baseFunc3( foo );
}
}