В Java мы можем создать такой класс утилит:
final class Utils {
public static boolean foo() {
return false;
}
}
Но как это сделать в Котлине?
Я пытаюсь использовать функции внутри object:
object Utils {
fun foo(): Boolean {
return false
}
}
Но при вызове этого метода из кода Java необходимо добавить INSTANCE. Пример: Utils.INSTANCE.foo().
Затем я объявляю его функцией верхнего уровня (без class или object):
@file:JvmName("Utils")
@file:JvmMultifileClass
fun foo(): Boolean {
return true
}
Затем я могу вызвать Utils.foo() из кода Java. Но из кода Kotlin я получил ошибку компилятора Unresolved reference. Допускается только прямое использование функции foo() (без префикса Utils).
Итак, как лучше всего объявить класс utils в Котлине?





Для этого вам нужно использовать @JvmStatic:
В Котлине:
object Utils {
@JvmStatic
fun foo(): Boolean = true
}
val test = Utils.foo()
В Java:
final boolean test = Utils.foo()
Спасибо, может быть, стиль Java (UtilsClass.utilsFunc()) не так хорош с Kotlin, потому что часть UtilsClass избыточна, верно?
Что ж, тут вопрос вкуса / стиля. Как указал @ zsmb13, вы можете получить этот синтаксис в Java с помощью @JvmName и использовать объявление верхнего уровня в Kotlin. Некоторые люди по-прежнему предпочитают именованный объект даже в Kotlin, поскольку он обеспечивает более согласованный стиль в многоязычном проекте.
Я один из тех, кто все еще предпочитает названный объект даже в Котлине. xD
Обратите внимание, что класс util, который вы использовали в Java, был единственным способом предоставить там дополнительные функции для всего, что не принадлежало определенному типу или объекту. Использование object для этого в Kotlin не имеет смысла. Это не синглтон, правда?
Второй подход, о котором вы упомянули, скорее подходит для служебных функций. Внутри такие функции переводятся в статические, и, как вы можете видеть, они становятся статическими служебными классами в Java, которые вы ищете, поскольку у вас не может быть автономных функций в Java без класса или перечисления. Однако в самом Котлине это просто функции.
Некоторые даже считают служебные классы антишаблонами. С другой стороны, функции имеют смысл без класса или объекта, имя которого в любом случае не имеет большого значения.
Я знаком со стилем Java (UtilsClass.utilsFunc()), который объединяет функции с относительным значением в один и тот же класс (для простоты управления). Но в Котлине это не лучший подход, правда?
да. В то время как в Java у вас не было другого способа предоставить такие функции, в Kotlin у вас есть. В Java у вас может быть хотя бы статический импорт, чтобы скрыть имя служебного класса, и тогда использование в Java будет выглядеть так же, как и в Kotlin. Это, вероятно, лучший подход, чем наоборот.
Последнее решение, которое вы предложили, на самом деле довольно идиоматично в Kotlin - вам не нужно ограничивать вашу функцию внутри чего-либо, функции верхнего уровня отлично подходят для использования утилит, на самом деле, это то, из чего состоит большая часть стандартной библиотеки.
Вы также правильно использовали аннотацию @JvmName, именно так вы должны сделать эти функции верхнего уровня легко вызываемыми для пользователей Java.
Обратите внимание, что @JvmMultifileClass вам нужен только в том случае, если вы помещаете свои функции верхнего уровня в разные файлы, но все же хотите, чтобы они в конечном итоге сгруппировались в одном файле класса (опять же, только для пользователей Java). Если у вас есть только один файл или вы даете каждому файлу разные имена, эта аннотация вам не нужна.
Если по какой-то причине вам нужен один и тот же синтаксис Utils.foo() как в Java, так и в Kotlin, решение с object, а затем @JvmStatic для каждого метода - способ сделать это, как уже было показано @marianosimone в этот ответ.
Дополнительная информация из ответа @Roland: использование object для утилит в Kotlin не имеет никакого смысла. Это не синглтон, правда? Спасибо вам всем\
Этот вопрос становится известным, я опубликовал для него статью здесь