Если вы пришли из мира Java, вы уже знакомы со статическими методами. Они не позволяют нам копировать наши методы в каждый класс и позволяют использовать их без создания объекта. Но что, если я скажу вам, что в Котлине нет статических методов ?!
Правда. Но это не означает, что мы не можем воспользоваться преимуществами статических методов в Kotlin. Есть способ их обойти. Посмотрим как.
В документации Kotlin рекомендуется использовать функции уровня пакета, если вы хотите следовать DRY. Это может показаться немного странным, если вы работали с Java, потому что в Java ее нет! Давайте создадим функцию на уровне пакета в Kotlin. Все, что вам нужно сделать, это создать файл с расширением .kt и поместить метод, который вы будете использовать, в нескольких местах. Я создам файл с именем SampleClass.kt. Содержимое SampleClass.kt:
package packageA fun bar(){ println("Method bar") }
Как видите, нам не нужно было помещать наш метод bar () в какое-либо объявление класса верхнего уровня. Если вы посмотрите на декомпилированный код, он выглядит следующим образом:
public final class SameClassKt { public static final void bar() { String var0 = "Method bar"; System.out.println(var0); } }
Несмотря на то, что мы не помещали его ни в какое объявление класса, Kotlin при компиляции создаст класс с именем SampleClassKt и поместит в него метод. И обратите внимание на сигнатуру нашего метода: public static final void bar () Именно то, что мы хотели иметь!
Если вы хотите вызвать эту функцию из любого другого класса, скажем HelloWorld.kt, вы можете вызвать ее, выполнив:
package packageB import packageA.bar fun main(args: Array<String>) { bar() }
Обратите внимание, что мы должны импортировать этот метод из его пакета, отсюда и оператор import packageA.bar.
Другой способ сделать это - поместить метод в объявление объекта.
package packageA object Foo{ fun bar() = println("Method bar") var foo="foo" }
И вы можете получить к нему доступ, например:
Foo.bar()
Объявление объекта в основном используется внутри класса, оно полезно, если вы хотите получить доступ к внутренним компонентам класса. Чтобы лучше понять это, давайте посмотрим его декомпилированный код:
public final class Foo { public static final Foo INSTANCE; public final void bar() { String var1 = "Method bar"; System.out.println(var1); } private Foo() { INSTANCE = (Foo)this; } static { new Foo(); } }
Любые методы или переменные в объявлении объекта будут работать как статический метод или переменная.
Если вы посмотрите на приведенный выше код, у нас есть статический блок, который будет выполняться, когда класс загружается в память, этот блок создает объект Foo. Обратите внимание, что конструктор является частным, поэтому объект может быть создан только внутри класса. Звонит в колокол? Таким образом мы получаем класс Singleton!
Но если вы хотите сделать это так же, как в старом стиле Java, то есть используя имя класса в качестве квалификатора, вам понадобится идентификатор компаньона.
class SampleClass{ companion object { fun bar()= print("Bar method") } }
А затем вы можете получить к нему доступ из кода Kotlin, используя тот же синтаксис, что и в Java. т.е.
SampleClass.foo()
Следует отметить, что если вы вызываете метод под объектом-компаньоном из кода Java, вам нужно будет поместить идентификатор сопутствующего объявления между именем класса и именем метода. например
SampleClass.Companion.foo();
Если вы не хотите помещать идентификатор компаньона между ними, вы также можете дать имя своему объекту
companion object Foo{ fun foo()= print("In foo method") }
А затем вызовите его с помощью SampleClass.Foo.foo ().
Если вы хотите избавиться от идентификатора Companion, а также не хотите давать какое-либо имя своему объекту, вам необходимо разместить аннотацию @JvmStatic с именем метода.
class SampleClass{ companion object { @JvmStatic fun foo()= print("In foo method") } }
Тогда вы также можете вызвать его как SampleClass.foo () из кода Java.
Прежде чем закрыть эту тему, давайте посмотрим, как разрешать функции расширения статически. Если вы не знакомы с функциями расширения, попросту говоря, это методы, определенные вне класса, но ведут себя так, как если бы они были функциями-членами. Посмотрите пример ниже:
fun main(args: Array<String>) { val sampleClass=SampleClass() sampleClass.foo() } class SampleClass{ } private fun SampleClass.foo() { println("saas") }
Как видите, мы обращались к методу foo (), как если бы он был частью SampleClass.
В любом случае, теперь мы попытаемся получить доступ к функциям расширения статически. Для этого нам нужно поместить в класс пустой объект-компаньон.
class SampleClass{ companion object }
Чтобы определить функцию расширения, которая может вызываться статически, нам нужно поместить идентификатор Companion между классом получателя и именем метода:
private fun SampleClass.Companion.foo() { println("saas") }
Теперь мы можем вызвать функцию расширения, не создавая объект класса получателя:
SampleClass.foo()
Если вы посмотрите на декомпилированный код, то увидите, что это почти то, что мы хотели:
private static final void foo(@NotNull SampleClass.Companion $receiver) { String var1 = "saas"; System.out.println(var1); }
Полезные ссылки:
Документация Котлина
Блог команды JetBrains, обсуждающей статические константы в Kotlin.
Статические константы в Kotlin
Kotlin разработан таким образом, что в классе нет такой вещи, как« статический член . Если у вас есть функция в классе, она… blog.jetbrains.com »
Отличная ветка abreslav о статическом разрешении функции расширения.