0

我有一些Drawers泛型:

abstract class BaseGeoDrawer<KEY : Any, GEO : Any, ITEM : Any>

abstract class BasePolygonDrawer<KEY : Any, ITEM : Any>: BaseGeoDrawer<KEY, Polygon, ITEM>
class TeamAreaDrawer : BasePolygonDrawer<String, Team>

abstract class BaseMarkerDrawer<KEY : Any, ITEM : Any> : BaseGeoDrawer<KEY, Marker, ITEM>
class TeamPositionDrawer : BaseMarkerDrawer<String, Team>

然后我有一个controller接受这些Drawers,把它们放在一个ArrayList

private val drawers = ArrayList<BaseGeoDrawer<Any, Any, Any>>()
open fun addGeoDrawer(drawer: BaseGeoDrawer<Any, Any, Any>) {
    drawers.add(drawer)
}

稍后在这些中调用方法Drawers

//Method in controller
private fun onMarkerClicked(marker: Marker): Boolean {
    return drawers.any { it.onGeoClicked(marker) }
}

//Method in BaseGeoDrawer
fun onGeoClicked(geo: GEO): Boolean

问题出现在这一行

teamAreaDrawer = TeamAreaDrawer(this)
mapController.addGeoDrawer(teamAreaDrawer)

Android Studio 不允许,告诉我

Type mismatch.
Required: BaseGeoDrawer<Any, Any, Any>
Found: TeamAreaDrawer

我试过用drawers

private val drawers = ArrayList<BaseGeoDrawer<out Any, out Any, out Any>>()

但是随后onMarkerClicked将无法编译,并出现以下错误

Out-projected type BaseGeoDrawer<out Any, out Any, out Any> prohibits the use of 'public final fun onGeoClicked(geo: GEO) defined in mypackage.BaseGeoDrawer'
4

1 回答 1

1

这里的问题是您需要GEO作为逆变类型参数BaseGeoDrawer来使用onGeoClicked(GEO),但它的类型ArrayList<BaseGeoDrawer<Any, Any, Any>>不变的。这意味着您不能添加除BaseGeoDrawer<Any, Any, Any>. 如果您尝试使用BaseGeoDraweras协变的类型,它将无法编译,因为您在调用时需要它作为逆变onGeoClicked(GEO)

考虑到到目前为止,在 Kotlin 中,类型参数不能是bivariant,唯一的方法是进行未经检查的强制转换。

在这种特定情况下,您可以执行以下操作:

val teamAreaDrawer = TeamAreaDrawer(this) as BaseGeoDrawer<Any, Any, Any>
mapController.addGeoDrawer(teamAreaDrawer)

如果您考虑一下,在 Java 中,您会做同样的事情,因为您会:

List<BaseGeoDrawer> drawers = new ArrayList<>();

public void example() {
    TeamAreaDrawer teamAreaDrawer = new TeamAreaDrawer();
    drawers.add(teamAreaDrawer);
    // This is an unchecked cast.
    drawers.get(0).onGeoClicked("Example");
}

我建议您在此处阅读有关方差的更多信息。

于 2017-10-06T19:25:33.250 回答