我有一些带有泛型的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'
答案 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的更多信息。