Kotlin: Как я могу создать "статическую" наследуемую функцию?

Например, я хочу иметь функцию example() для типа Child, который расширяет Parent, поэтому я могу использовать эту функцию для обоих.

Child.example()
Parent.example()

Первый "очевидный" способ сделать это - через сопутствующий объект Parent, но это не позволяет example() для Child.

Второй способ, которым я пытался, - определить функцию расширения на Parent.Companion, что неудобно, потому что вы вынуждены определять объект-компаньон. Он также не позволяет example() для Child.

Кто-нибудь знает, как я могу это сделать?

Ответ 1

То, о чем вы просите, не существует, вы, кажется, спрашиваете:

Можно ли ссылаться на метод сопутствующих объектов суперкласса из ссылки класса его потомков

или, возможно, вы спрашиваете:

Можно ли ссылаться на статический член суперкласса из ссылки его потомков.

Ответ для обоих - нет. дизайн Котлина, что это запрещено, было сознательным решением, было преднамеренным. Если вы хотите изменить это решение, вам нужно удалить файл в YouTrack. Программисты на Java были сильно запутаны путем наследования и переопределения статических методов и поведения при вызове из одной ссылки по сравнению с другой и как она статически разрешена, а не динамически. Команда Java 8 при добавлении статических методов в интерфейсы реализует путаницу, которая может привести к этому, поэтому они приняли более подход Kotlin, только позволяя ему вызываться по ссылке интерфейса. Чтобы избежать этих кошмаров, команда Котлина не разрешала это. Так же, как они запретили многие другие запутывающие аспекты Java.

Другие ответы (например, @voddan) дают вам обходные ситуации, чтобы иметь синтаксис синтаксиса, используя объекты-компаньоны, но вы отклоняете их в своих комментариях, говоря, что хотите избежать сопутствующего объекта, хотя в вашем вопросе утверждается, что вы пытаетесь их использовать. Поэтому, полагая, что вы не хотите их использовать, ответ просто нет, не может быть сделано.

Чтобы избавиться от объекта-компаньона, вы хотели бы поговорить о Можно ли вызывать функции расширения со статическим способом?... что будет неутешительно поскольку он еще не разрешен.

Возвращаясь к сопутствующим объектам (извините, но они являются одним из путей к славе здесь), вы можете просто вручную делегировать метод дочернего элемента родительскому:

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 вы должны использовать Factory вместо статического метода при использовании в качестве "конструктора".

На стороне Котлина вы можете использовать функцию верхнего уровня вместо Factory.

Или, если вы действительно хотите иметь "статический метод" в своем классе, Я бы создал объект-компаньон и добавил статические методы расширения.