Kotlin和泛型混淆

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

然后我有一个接受这些Drawerscontroller ,把它们放在一个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' 

这里的问题是,您需要将GEO作为BaseGeoDrawer逆变类型参数在BaseGeoDrawer onGeoClicked(GEO)但是ArrayList<BaseGeoDrawer<Any, Any, Any>>在其类型中是不变的 。 这意味着您不能添加任何比BaseGeoDrawer<Any, Any, Any> 。 如果您尝试使用BaseGeoDrawer的类型作为协变 ,它将不会编译,因为当您调用onGeoClicked(GEO)时,您需要它作为逆变

考虑到直到现在在科特林,一个类型参数不能是双变量的 ,唯一的办法就是做一个不受控制的转换。

在这个特定的情况下,你可以这样做:

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

我建议你阅读更多关于这里的变化。