【问题标题】:Kotlin: How can I create a "static" inheritable function?Kotlin:如何创建“静态”可继承函数?
【发布时间】:2016-09-03 04:17:00
【问题描述】:

例如,我想在扩展 Parent 的类型 Child 上拥有一个函数 example(),以便我可以在两者上使用该函数。

Child.example()
Parent.example()

第一个“明显”的方法是通过Parent 的伴随对象,但这不允许example() 用于Child

我尝试的第二种方法是在Parent.Companion 上定义一个扩展函数,这很不方便,因为你不得不定义一个伴生对象。它也不允许example() 用于Child

有人知道我该怎么做吗?

【问题讨论】:

  • 让静态函数可继承有什么意义???
  • @DanielTran 好吧,它不一定是“静态的”,因为它是 Kotlin。目的是为构造创建一个“替代运算符”,例如 Child[1, 2, 3] 而不是 Child(1, 2, 3)
  • @DanielTran 例如为子类强制执行工厂方法怎么样?

标签: function kotlin


【解决方案1】:

你要的东西不存在,你似乎在问:

我是否可以从其后代的类引用中引用超类的伴随对象方法

或者你可能在问:

我可以从其后代的引用中引用超类的静态成员吗​​?

两者的答案都是。这是 Kotlin 的设计,这是不允许的,是有意识的决定,是故意的。如果你想改变这个决定,你需要file an issue in YouTrack。 Java 程序员对于静态方法的继承和覆盖,以及从一个引用与另一个引用调用时的行为,以及它是如何静态解析而不是动态解析的,非常困惑。 Java 8 团队在向接口添加静态方法时意识到这可能会导致混乱,因此他们采用了更 Kotlin 的方法,只允许接口引用调用它。为了避免这些类型的噩梦,Kotlin 团队不允许这样做。正如他们不允许 Java 的许多其他令人困惑的方面一样。

其他答案(例如@voddan 的答案)为您提供了解决方法,以通过使用companion objects 来获得与调用语法相同的感觉,但您拒绝在您的 cmets 中说您想要避免伴随对象,即使您的问题表明您正在尝试使用它们。因此,假设您不想使用它们,答案就是不,无法完成

要摆脱伴​​随对象,你会想谈论Can extension functions be called in a “static” way? ...这将是令人失望的,因为它还不允许。

回到伴生对象(对不起,它们是通往荣耀的唯一途径),您也可以手动将子对象的方法委托给父对象:

open class Parent {
    companion object { // required, sorry, no way around it!
        fun foo() = /* some cool logic here */
    }
}

class Child: Parent() {
    companion object {  // required, sorry, no way around it!
        fun foo() = Parent.foo() 
    }
}

或作为扩展:

open class Parent {
    companion object {} // required, sorry, no way around it!
}

class Child: Parent() {
    companion object {} // required, sorry, no way around it!
}

fun Parent.Companion.foo() = /* some cool logic here */
fun Child.Companion.foo() = Parent.foo()

【讨论】:

    【解决方案2】:

    由于伴随对象的运行规则与任何其他对象相同,因此很容易对它们使用正常的代码重用方法:

    open class Example {
        fun example() {}
    }
    
    class Parent {
        companion object : Example()
    }
    
    class Child {
        companion object : Example()
    }
    
    fun main(args: Array<String>) {
        Child.example()
        Parent.example()
    }
    

    或者使用类委托,您可以直接重用来自Parent 的实现:

    interface Example {
        fun example()
    }
    
    class Parent {
        companion object : Example {
            override fun example() {}
        }
    }
    
    class Child {
        companion object : Example by Parent.Companion
    }
    

    【讨论】:

    • 有什么办法可以避免必须定义伴生对象吗?
    • 它可能是一个普通的对象;)
    【解决方案3】:

    目的是为构造创建一个“替代运算符”

    在 Java 中,当用作“构造函数”时,您应该使用工厂而不是静态方法。

    在 Kotlin 方面,您可以使用顶级函数而不是工厂。

    或者如果你真的想在你的类中有一个“静态方法”, 我会创建一个伴随对象并添加静态扩展方法。

    【讨论】:

    • 你说的都对,但是子类不能用。
    • 你错过了扩展功能的导入吗?导入静态扩展函数后,子类中应该可以使用它
    • 对不起,我应该措辞更好。我的意思是你不能自动将它们用于子类。就像在名为Parent 的父对象的伴随对象中定义函数example() 一样,您可以执行Parent.example();如果Parent 的孩子称为Child,则不能自动执行Child.example()
    • 你是对的,它甚至不能使用静态扩展函数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 2021-08-13
    • 2014-06-26
    • 1970-01-01
    • 2017-07-03
    • 2013-12-20
    • 1970-01-01
    相关资源
    最近更新 更多