Kotlin和仿制药混淆

时间:2017-10-06 11:33:21

标签: android generics kotlin kotlin-generics

我有一些带有泛型的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'

1 个答案:

答案 0 :(得分:1)

此处的问题是您需要GEO作为BaseGeoDrawer中的逆变类型参数才能使用onGeoClicked(GEO),但ArrayList<BaseGeoDrawer<Any, Any, Any>>类型中不变的。这意味着您无法添加除BaseGeoDrawer<Any, Any, Any>之外的任何内容。如果您尝试将BaseGeoDrawer类型用作协变,则无法编译,因为当您致电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");
}

我建议您阅读有关差异here的更多信息。