考虑以下接口和类:

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 );
    }
}

09-04 19:34