如何处理Kotlin中的多态性

时间:2018-12-27 22:03:54

标签: kotlin polymorphism abstract-class

我正在处理一个抽象类和两个具体的类,它们实现了抽象类。下图如下: enter image description here

我的课程如下:

abstract class NavItem() {
    var attributes: String = ""
    var text = ""
}

class NavMenu(val items: MutableList<NavItem>) : NavItem()

class NavLink(var shortText: String) : NavItem()

问题是,当我尝试使用可能是NavMenu或NavLinks的项目时,NavMenus有一个NavLinks集合。

我正在尝试使用多态性作为下一个代码的项目:

navMenu.items.forEach{ item ->
            buildNavItem(item)
        }

buildNavItem方法似乎是:

private fun buildNavItem(navMenu: NavMenu){
        navMenu.items
        navMenu.attributes
        navMenu.items
    }

    private fun buildNavItem(navItem: NavItem){
        navItem.text
        navItem.attributes
    }

    private fun buildNavItem(navLink: NavLink){
        navLink.text
        navLink.attributes
    }

但是代码总是进入buildNavItem(navItem:NavItem)中,即使在每个代码中我有时也会看到该项目是NavLink或NavMenu。

有什么建议吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

这不是多态的工作原理。您拥有navMenu.items类型的MutableList<NavItem>列表,它可以存储NavItem或其后代。在forEach函数中,您将浏览具有NavItem类型的每个项目,然后调用buildNavItem(item)函数。在这种情况下,总是调用buildNavItem(navItem: NavItem)。要使用另一个参数调用同一方法,您需要将其显式转换为该类型。我建议(即多态性如何工作)是在buildNavItem()类中创建NavItem函数,并在后代中实现它:

abstract class NavItem() {
    var attributes: String = ""
    var text = ""
    abstract fun buildNavItem()
}

class NavMenu(val items: MutableList<NavItem>) : NavItem() {
    override fun buildNavItem() {
        // ... your concrete implementation for NavMenu
    }
}

class NavLink(var shortText: String) : NavItem() {
    override fun buildNavItem() {
        // ... your concrete implementation for NavLink
    }
}

然后您可以在forEach函数中调用它:

navMenu.items.forEach { item ->
        item.buildNavItem()
}

在那种情况下,将为存储在buildNavItem()中的正确对象调用navMenu.items函数,即,如果它是NavLink类型的对象,则函数'buildNavItem()'在NavLink类中重写的,将被调用。

答案 1 :(得分:-1)

问题:

navMenu.items.forEach { item ->
    item.buildNavItem()
}

由于items的类型为List<NavMenu>,因此编译器将调用适用于类型item的{​​{1}}的函数,在这种情况下,重载将导致NavMenu

解决方案:

为了调用更具体的重载,编译器需要知道类型。您可以智能地投射项目,然后调用适当的函数:

NavMenu

通过这种方式,只要您调用private fun buildNavItem(navMenu: NavMenu) { when(navMenu){ is NavItem -> buildNavItem(navMenu) // navMenu is smart casted to NavItem is NavLink -> buildNavItem(navMenu) // navMenu is smart casted to NavLink else -> throw IllegalStateException("Unknown subtype ${navMenu::class.simpleName} of NavMenu") } } ,就可以委派给适当的函数。