Вы создали конфликт между вашими объявлениями Map
и ItemParser
. Карта может содержать любого потомка BaseItem
, но ItemParser
предназначен для того, чтобы каждый потомок работал только на один потомков BaseItem
. Таким образом, для данного экземпляра ItemParser
он должен принять что-то, что он может распознать, и здесь вы не можете этого сделать, потому что ваш foundParser
может быть любым потомком, а не единственным истинно ожидаемым типом для данного данного ItemParser
экземпляра. Какой T
он должен угадать?!? Не может.
Поэтому вы должны разрабатывать свой API на основе базового класса, а не потомков. Вы лишаете компилятор возможности узнать, что передается методу parse()
. Единственная истинная вещь, которую вы можете знать, это то, что это BaseItem
экземпляр.
Только вы знаете, что вы делаете с картой, которая гарантирует, что вы вызываете правильный экземпляр с правильным типом. Компилятор не имеет представления о вашей логике, которая делает это гарантией.
Я бы посоветовал вам изменить свой API, добавив internalParse
метод, для которого вы выполняете приведение, выполняющий свою работу, обернутый общей функцией parse
, которая дважды проверяет и выполняет приведение зла.
abstract class BaseItem
class AmericanItem : BaseItem()
class EuropeanItem : BaseItem()
interface ItemParser<T: BaseItem> {
@Suppress("UNCHECKED_CAST")
fun parse(item: BaseItem) {
val tempItem = item as? T
?: throw IllegalArgumentException("Invalid type ${item.javaClass.name} passed to this parser")
internalParse(tempItem)
}
fun internalParse(item: T)
}
class AmericanItemParser : ItemParser<AmericanItem> {
override fun internalParse(item: AmericanItem) {
println("AmericanItemParser")
}
}
class EuropeanItemParser : ItemParser<EuropeanItem> {
override fun internalParse(item: EuropeanItem) {
println("parsing EuropeanItem")
}
}
fun main(args: Array<String>) {
val hashMap = HashMap<Class<out BaseItem>, ItemParser<*>>()
hashMap.put(AmericanItem::class.java, EuropeanItemParser())
hashMap.put(EuropeanItem::class.java, AmericanItemParser())
val inputItem = EuropeanItem()
val foundParser = hashMap[inputItem.javaClass]
foundParser?.parse(inputItem)
}
Обратите внимание, что вы также можете использовать класс Kotlin вместо класса Java, который будет иметь тип KClass<out T>
.