Вызов Java из Kotlin
Kotlin разработан с учетом взаимодействия с Java. Существующий код Java может вызываться из Kotlin естественным образом, и код Kotlin может использоваться из Java также достаточно гладко. В этом разделе мы описываем некоторые детали вызова Java-кода из Kotlin.
Практически весь Java-код может использоваться без каких-либо проблем:
import java.util.*
fun demo(source: List<Int>) {
val list = ArrayList<Int>()
// 'for'-loops work for Java collections:
for (item in source) {
list.add(item)
}
// Operator conventions work as well:
for (i in 0..source.size - 1) {
list[i] = source[i] // get and set are called
}
}
Геттеры и сеттеры
Методы, которые следуют соглашениям Java для геттеров и сеттеров (методы без аргументов с именами, начинающимися с get и методы с одним аргументом с именами, начинающимися с set), представляются как свойства в Kotlin. Boolean методы доступа (где имя геттера начинается с is и имя сеттера начинается с set ) представляются как свойства, имеющие то же имя, что и метод геттера.
import java.util.Calendar
fun calendarDemo() {
val calendar = Calendar.getInstance()
if (calendar.firstDayOfWeek == Calendar.SUNDAY) { // call getFirstDayOfWeek()
calendar.firstDayOfWeek = Calendar.MONDAY // call setFirstDayOfWeek()
}
if (!calendar.isLenient) { // call isLenient()
calendar.isLenient = true // call setLenient()
}
}
Обратите внимание, что если в Java-классе есть только сеттер, он не отображается как свойство в Kotlin, потому что Kotlin не поддерживает свойства только для записи.
Методы, возвращающие void
Если Java-метод возвращает void, он вернет Unit при вызове из Kotlin. Если по какой-либо причине кто-то использует это возвращаемое значение, оно будет назначено в месте вызова компилятором Kotlin, так как само значение известно заранее (будучи Unit).
Экранирование для Java-идентификаторов, являющихся ключевыми словами в Kotlin
Некоторые ключевые слова Kotlin являются допустимыми идентификаторами в Java: in, object, is, и другие. Если Java-библиотека использует ключевое слово Kotlin для метода, вы все равно можете вызвать метод, экранировав его символом обратной косой черты ( ` ):
foo.`is`(bar)
Безопасность от null и платформенные типы
Любая ссылка в Java может быть null, что делает требования Kotlin к строгой безопасности от null непрактичными для объектов, поступающих из Java. Типы Java-объявлений обрабатываются в Kotlin специфичным образом и называются платформенными типами. Проверки на null ослабляются для таких типов, так что гарантии безопасности для них такие же, как в Java (см. подробнее ниже).
Рассмотрим следующие примеры:
val list = ArrayList<String>() // non-null (constructor result)
list.add("Item")
val size = list.size // non-null (primitive int)
val item = list[0] // platform type inferred (ordinary Java object)
При вызове методов на переменных платформенных типов Kotlin не генерирует ошибок неявной применимости null во время компиляции, но вызов может завершиться сбоем во время выполнения из-за исключения null-указателя или утверждения, которое Kotlin генерирует для предотвращения распространения null:
item.substring(1) // allowed, may throw an exception if item == null
Платформенные типы являются необозначаемыми, что означает, что вы не можете записать их явно в языке. Когда платформное значение присваивается переменной Kotlin, вы можете положиться на вывод типа (переменная затем будет иметь выведенный платформенный тип, как item в приведенном выше примере), или вы можете выбрать ожидаемый тип (разрешены как nullable, так и non-null типы):
val nullable: String? = item // allowed, always works val notNull: String = item // allowed, may fail at runtime
Если вы выберете тип non-null, компилятор выведет утверждение при присваивании. Это предотвращает попадание null в переменные Kotlin, не допускающие null. Утверждения также генерируются при передаче платформных значений в функции Kotlin, ожидающие non-null значения, и в других случаях. В целом, компилятор делает все возможное, чтобы предотвратить распространение null по всему коду, хотя иногда это невозможно полностью устранить из-за дженериков.
Обозначение платформенных типов
Как упоминалось выше, платформенные типы не могут быть упомянуты явно в программе, поэтому для них нет синтаксиса в языке. Тем не менее, компилятору и IDE необходимо иногда отображать их (например, в сообщениях об ошибках или информации о параметрах), поэтому для них есть мнемоническое обозначение:
T!означает "TилиT?",(Mutable)Collection<T>!означает "коллекция Java типаTможет быть изменяемой или нет, может быть nullable или нет",Array<(out) T>!означает "массив Java типаT(или подтипT), nullable или нет"
Аннотации применимости null
Типы Java, имеющие аннотации применимости null, представляются не как платформенные типы, а как фактические nullable или non-null типы Kotlin. Компилятор поддерживает несколько вариантов аннотаций применимости null, включая:
JetBrains (
@Nullableи@NotNullиз пакетаorg.jetbrains.annotations)JSpecify (
org.jspecify.nullness)Android (
com.android.annotationsиandroid.support.annotations)JSR-305 (
javax.annotation, подробности ниже)FindBugs (
edu.umd.cs.findbugs.annotations)Eclipse (
org.eclipse.jdt.annotation)Lombok (
lombok.NonNull)RxJava 3 (
io.reactivex.rxjava3.annotations)
Вы можете указать, сообщает ли компилятор о несовпадении применимости null, основываясь на информации из определенных типов аннотаций применимости null. Используйте компиляционную опцию -Xnullability-annotations=@<package-name>:<report-level>. В аргументе укажите полный квалифицированный пакет аннотаций применимости null и один из этих уровней отчета:
ignoreдля игнорирования несовпадений применимости nullwarnдля отчета о предупрежденияхstrictдля отчета об ошибках.
Полный список поддерживаемых аннотаций применимости null см. в исходном коде компилятора Kotlin.
Аннотирование аргументов и параметров типа
Вы можете аннотировать аргументы и параметры типа для общих типов, чтобы также предоставить информацию о применимости null для них.
Аргументы типа
Рассмотрим эти аннотации в Java-объявлении:
@NotNull
Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements) { ... }
Они приводят к следующему виду в Kotlin:
fun toSet(elements: (Mutable)Collection<String>) : (Mutable)Set<String> { ... }
Когда аннотация @NotNull отсутствует в аргументе типа, вместо этого получается платформенный тип:
fun toSet(elements: (Mutable)Collection<String!>) : (Mutable)Set<String!> { ... }
Kotlin также учитывает аннотации применимости null в аргументах типа базовых классов и интерфейсов. Например, существуют два Java-класса со следующими сигнатурами:
public class Base<T> {}
public class Derived extends Base<@Nullable String> {}
В Kotlin-коде передача экземпляра Derived , где предполагается Base<String> , порождает предупреждение.
fun takeBaseOfNotNullStrings(x: Base<String>) {}
fun main() {
takeBaseOfNotNullStrings(Derived()) // warning: nullability mismatch
}
Верхняя граница Derived установлена в Base<String?>, что отличается от Base<String>.
Дополнительную информацию об Java-дженериках в Kotlin см. ниже.
Параметры типа
По умолчанию применимость null простых параметров типа в Kotlin и Java не определена. В Java вы можете указать ее с помощью аннотаций применимости null. Давайте аннотируем параметр типа класса Base:
public class Base<@NotNull T> {}
При наследовании от Base, Kotlin ожидает non-nullable аргумент или параметр типа. Таким образом, следующий Kotlin-код генерирует предупреждение:
class Derived<K> : Base<K> {} // warning: K has undefined nullability
Вы можете исправить это, указав верхнюю границу K : Any.
Kotlin также поддерживает аннотации применимости null для границ Java-параметров типа. Давайте добавим границы к Base:
public class BaseWithBound<T extends @NotNull Number> {}
Kotlin переводит это следующим образом:
class BaseWithBound<T : Number> {}
Таким образом, передача nullable типа в качестве аргумента или параметра типа порождает предупреждение.
Аннотирование аргументов и параметров типа работает с Java 8 или более поздней версией. Для этого необходимо, чтобы аннотации применимости null поддерживали цель TYPE_USE (org.jetbrains.annotations поддерживает это в версии 15 и выше). Используйте компиляционную опцию -Xtype-enhancement-improvements-strict-mode для отчета об ошибках в Kotlin-коде, использующем применимость null, которая отличается от аннотаций применимости null из Java.
Поддержка JSR-305
Аннотация @Nonnull, определённая в JSR-305, поддерживается для обозначения возможности null-значений для типов Java.
Если значение @Nonnull(when = ...) равно When.ALWAYS, аннотированный тип обрабатывается как не допускающий null-значений; When.MAYBE и When.NEVER обозначают тип, допускающий null-значения; а When.UNKNOWN принудительно делает тип платформенным платформенным.
Библиотека может быть скомпилирована с аннотациями JSR-305, но нет необходимости делать артефакт аннотаций (например, jsr305.jar) зависимостью от компиляции для потребителей библиотеки. Компилятор Kotlin может считывать аннотации JSR-305 из библиотеки без наличия аннотаций в пути к классам.
Пользовательские квалификаторы для null-значений (KEEP-79) также поддерживаются (см. ниже).
Псевдонимы квалификаторов типов
Если тип аннотации аннотирован как @TypeQualifierNickname и JSR-305 @Nonnull (или его другим псевдонимом, например, @CheckForNull), то тип аннотации сам используется для получения точного значения null-значений и имеет то же значение, что и аннотация null-значений:
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNonnull {
}
@TypeQualifierNickname
@CheckForNull // a nickname to another type qualifier nickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNullable {
}
interface A {
@MyNullable String foo(@MyNonnull String x);
// in Kotlin (strict mode): `fun foo(x: String): String?`
String bar(List<@MyNonnull String> x);
// in Kotlin (strict mode): `fun bar(x: List<String>!): String!`
}
Значения по умолчанию для квалификаторов типов
@TypeQualifierDefault позволяет вводить аннотации, которые, при применении, определяют значение по умолчанию для null-значений в рамках аннотированного элемента.
Такой тип аннотации должен сам быть аннотирован как @Nonnull (или его псевдонимом) и @TypeQualifierDefault(...) с одним или несколькими значениями ElementType:
ElementType.METHODдля типов возвращаемых значений методовElementType.PARAMETERдля параметров значенияElementType.FIELDдля полейElementType.TYPE_USEдля любого типа, включая аргументы типов, верхние границы параметров типов и подстановочные типы
Значение по умолчанию для null-значений используется, когда сам тип не аннотирован аннотацией для null-значений, и значение по умолчанию определяется самым внутренним содержащим элементом, аннотированным аннотацией значения по умолчанию для квалификатора типа с ElementType соответствующим использованию типа.
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
@Nonnull(when = When.MAYBE)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE})
public @interface NullableApi {
}
@NullableApi
interface A {
String foo(String x); // fun foo(x: String?): String?
@NotNullApi // overriding default from the interface
String bar(String x, @Nullable String y); // fun bar(x: String, y: String?): String
// The List<String> type argument is seen as nullable because of `@NullableApi`
// having the `TYPE_USE` element type:
String baz(List<String> x); // fun baz(List<String?>?): String?
// The type of `x` parameter remains platform because there's an explicit
// UNKNOWN-marked nullability annotation:
String qux(@Nonnull(when = When.UNKNOWN) String x); // fun baz(x: String!): String?
}
Поддерживается также значение по умолчанию для null-значений на уровне пакета:
// FILE: test/package-info.java @NonNullApi // declaring all types in package 'test' as non-nullable by default package test;
Аннотация @UnderMigration
Аннотация @UnderMigration (предоставленная в отдельном артефакте kotlin-annotations-jvm) может быть использована разработчиками библиотек для определения статуса миграции для квалификаторов типов null-значений.
Значение статуса в @UnderMigration(status = ...) определяет, как компилятор обрабатывает ненадлежащее использование аннотированных типов в Kotlin (например, использование значения типа, аннотированного @MyNullable, в качестве значения, не допускающего null):
MigrationStatus.STRICTделает аннотацию работающей как любая обычная аннотация null-значений, т.е. сообщает об ошибках при ненадлежащем использовании и влияет на типы в аннотированных объявлениях так, как они видны в KotlinMigrationStatus.WARN: ненадлежащие использования сообщаются как предупреждения о компиляции, а не об ошибках, но типы в аннотированных объявлениях остаются платформеннымиMigrationStatus.IGNOREзаставляет компилятор полностью игнорировать аннотацию для null-значений
Разработчик библиотеки может добавить статус @UnderMigration к псевдонимам квалификаторов типов и значениям по умолчанию для квалификаторов типов:
@Nonnull(when = When.ALWAYS)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@UnderMigration(status = MigrationStatus.WARN)
public @interface NonNullApi {
}
// The types in the class are non-null, but only warnings are reported
// because `@NonNullApi` is annotated `@UnderMigration(status = MigrationStatus.WARN)`
@NonNullApi
public class Test {}
Если квалификатор типа по умолчанию использует псевдоним квалификатора типа, и оба являются @UnderMigration, используется статус от квалификатора типа по умолчанию.
Конфигурация компилятора
Проверки JSR-305 могут быть настроены путём добавления флага компилятора -Xjsr305 со следующими параметрами (и их комбинациями):
-Xjsr305={strict|warn|ignore}для установки поведения для аннотаций, не являющихся@UnderMigration. Пользовательские квалификаторы null-значений, особенно@TypeQualifierDefault, уже распространены среди многих известных библиотек, и пользователям может потребоваться плавная миграция при обновлении до версии Kotlin с поддержкой JSR-305. Начиная с Kotlin 1.1.60, этот флаг влияет только на аннотации, не являющиеся@UnderMigration.-Xjsr305=under-migration:{strict|warn|ignore}для переопределения поведения для@UnderMigrationаннотаций. У пользователей могут быть разные взгляды на статус миграции для библиотек: они могут захотеть получать ошибки, в то время как официальный статус миграцииWARN, или наоборот, они могут захотеть отложить сообщения об ошибках для некоторых, пока не завершат миграцию.-Xjsr305=@<fq.name>:{strict|warn|ignore}для переопределения поведения для одной аннотации, где<fq.name>- полностью квалифицированное имя класса аннотации. Может появляться несколько раз для разных аннотаций. Это полезно для управления состоянием миграции для конкретной библиотеки.
Значения strict, warn и ignore имеют то же значение, что и MigrationStatus, и только режим strict влияет на типы в аннотированных объявлениях так, как они видны в Kotlin.
Например, добавление -Xjsr305=ignore -Xjsr305=under-migration:ignore -Xjsr305=@org.library.MyNullable:warn в аргументы компилятора заставляет компилятор генерировать предупреждения о ненадлежащем использовании типов, аннотированных @org.library.MyNullable, и игнорировать все остальные аннотации JSR-305.
Поведение по умолчанию такое же, как -Xjsr305=warn. Значение strict следует рассматривать как экспериментальное (в будущем может быть добавлено больше проверок).
Сопоставленные типы
Kotlin обрабатывает некоторые типы Java специфическим образом. Такие типы не загружаются из Java "как есть", а сопоставляются с соответствующими типами Kotlin. Сопоставление имеет значение только во время компиляции, представление во время выполнения остается неизменным. Примитивные типы Java сопоставляются с соответствующими типами Kotlin (учитывая платформенные типы):
Тип Java |
Тип Kotlin |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Также сопоставляются некоторые встроенные классы, не являющиеся примитивными:
Java type |
Kotlin type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Упакованные примитивные типы Java сопоставляются с допускающими NULL типами Kotlin:
Java type |
Kotlin type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Обратите внимание, что упакованный примитивный тип, используемый в качестве параметра типа, сопоставляется с платформенным типом: например, List<java.lang.Integer> становится List<Int!> в Kotlin.
Типы коллекций могут быть только для чтения или изменяемыми в Kotlin, поэтому коллекции Java сопоставляются следующим образом (все типы Kotlin в этой таблице находятся в пакете kotlin.collections):
Java type |
Тип Kotlin (только для чтения) |
Изменяемый тип Kotlin |
Загруженный платформенный тип |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Массивы Java сопоставляются, как указано ниже:
Java type |
Kotlin type |
|---|---|
|
|
|
|
Обобщенные типы Java в Kotlin
Обобщенные типы Kotlin немного отличаются от обобщенных типов Java (см. Обобщенные типы). При импорте типов Java в Kotlin выполняются следующие преобразования:
-
Подстановочные знаки Java преобразуются в проекции типов:
Foo<? extends Bar>становитсяFoo<out Bar!>!Foo<? super Bar>становитсяFoo<in Bar!>!
-
Необработанные типы Java преобразуются в проекции со звездочкой:
ListстановитсяList<*>!, то естьList<out Any?>!
Как и в Java, обобщенные типы Kotlin не сохраняются во время выполнения: объекты не содержат информацию о фактических аргументах типа, переданных их конструкторам. Например, ArrayList<Integer>() неотличим от ArrayList<Character>(). Это делает невозможной проверку is, которая учитывает обобщенные типы. Kotlin разрешает только проверку is для типов с проекцией со звездочкой:
if (a is List<Int>) // Error: cannot check if it is really a List of Ints // but if (a is List<*>) // OK: no guarantees about the contents of the list
Массивы Java
Массивы в Kotlin являются неизменяемыми, в отличие от Java. Это означает, что Kotlin не позволит вам присвоить Array<String> типу Array<Any>, что предотвращает возможную ошибку во время выполнения. Передача массива подкласса как массива суперкласса в метод Kotlin также запрещена, но для методов Java это разрешено через платформенные типы вида Array<(out) String>!.
Массивы используются с примитивными типами данных на платформе Java для избежания затрат на операции boxing/unboxing. Поскольку Kotlin скрывает эти детали реализации, для взаимодействия с кодом Java требуется обходной путь. Существуют специализированные классы для каждого типа примитивного массива (IntArray, DoubleArray, CharArray, и так далее) для обработки этого случая. Они не связаны с классом Array и компилируются в примитивные массивы Java для максимальной производительности.
Предположим, есть метод Java, который принимает массив целых чисел индексов:
public class JavaArrayExample {
public void removeIndices(int[] indices) {
// code here...
}
}
Для передачи массива примитивных значений вы можете сделать следующее в Kotlin:
val javaObj = JavaArrayExample() val array = intArrayOf(0, 1, 2, 3) javaObj.removeIndices(array) // passes int[] to method
При компиляции в байт-код JVM компилятор оптимизирует доступ к массивам, чтобы не было накладных расходов:
val array = arrayOf(1, 2, 3, 4)
array[1] = array[1] * 2 // no actual calls to get() and set() generated
for (x in array) { // no iterator created
print(x)
}
Даже при навигации с индексом не возникает никаких накладных расходов:
for (i in array.indices) { // no iterator created
array[i] += 2
}
Наконец, in-проверки тоже не имеют накладных расходов:
if (i in array.indices) { // same as (i >= 0 && i < array.size)
print(array[i])
}
Java varargs
Классы Java иногда используют объявление метода для индексов с переменным числом аргументов (varargs):
public class JavaArrayExample {
public void removeIndicesVarArg(int... indices) {
// code here...
}
}
В этом случае вам необходимо использовать оператор spread * для передачи IntArray:
val javaObj = JavaArrayExample() val array = intArrayOf(0, 1, 2, 3) javaObj.removeIndicesVarArg(*array)
Операторы
Поскольку в Java нет способа отметить методы, для которых имеет смысл использовать синтаксис оператора, Kotlin позволяет использовать любые методы Java с соответствующим именем и сигнатурой в качестве перегрузок оператора и других соглашений (invoke() и т. д.). Вызов методов Java с помощью инфиксного синтаксиса вызова не разрешен.
Проверяемые исключения
В Kotlin все исключения являются непроверяемыми, что означает, что компилятор не заставляет вас их ловить. Таким образом, при вызове метода Java, который объявляет проверяемое исключение, Kotlin не заставляет вас ничего делать:
fun render(list: List<*>, to: Appendable) {
for (item in list) {
to.append(item.toString()) // Java would require us to catch IOException here
}
}
Методы объектов
При импорте типов Java в Kotlin все ссылки типа java.lang.Object преобразуются в Any. Поскольку Any не является специфичным для платформы, он объявляет только toString(), hashCode() и equals() в качестве своих членов, поэтому для того, чтобы сделать доступными другие члены java.lang.Object, Kotlin использует расширяющие функции.
wait()/notify()
Методы wait() и notify() недоступны для ссылок типа Any. Их использование обычно не рекомендуется в пользу java.util.concurrent. Если вам действительно нужно вызвать эти методы, вы можете выполнить приведение к типу java.lang.Object:
(foo as java.lang.Object).wait()
getClass()
Для получения класса Java объекта используйте расширяющее свойство java для ссылки на класс:
val fooClass = foo::class.java
В приведенном выше коде используется связанная ссылка на класс. Вы также можете использовать расширяющее свойство javaClass:
val fooClass = foo.javaClass
clone()
Для переопределения clone() ваш класс должен расширять kotlin.Cloneable:
class Example : Cloneable {
override fun clone(): Any { ... }
}
Не забывайте о Effective Java, 3-е издание, пункт 13: Переопределяйте clone разумно.
finalize()
Для переопределения finalize() вам просто нужно его объявить, не используя ключевое слово override:
class C {
protected fun finalize() {
// finalization logic
}
}
Согласно правилам Java, finalize() не должен быть private.
Наследование от классов Java
Максимум один класс Java (и любое количество интерфейсов Java) может быть супертипом для класса в Kotlin.
Доступ к статическим членам
Статические члены классов Java образуют «компаньоны объектов» для этих классов. Вы не можете передавать такой «компаньон объекта» как значение, но можете получить доступ к членам явно, например:
if (Character.isLetter(a)) { ... }
Для доступа к статическим членам типа Java, который сопоставлен с типом Kotlin, используйте полное квалифицированное имя типа Java: java.lang.Integer.bitCount(foo).
Рефлексия Java
Рефлексия Java работает с классами Kotlin и наоборот. Как упоминалось выше, вы можете использовать instance::class.java, ClassName::class.java или instance.javaClass для входа в рефлексию Java через java.lang.Class. Не используйте ClassName.javaClass для этой цели, поскольку она относится к классу компаньона ClassName, который эквивалентен ClassName.Companion::class.java, а не ClassName::class.java.
Для каждого примитивного типа существует два разных класса Java, и Kotlin предоставляет способы получения обоих. Например, Int::class.java вернёт экземпляр класса, представляющего сам примитивный тип, соответствующий Integer.TYPE в Java. Чтобы получить класс соответствующего оберточного типа, используйте Int::class.javaObjectType, что эквивалентно Integer.class в Java.
Другие поддерживаемые случаи включают получение метода получения/установки Java или вспомогательного поля для свойства Kotlin, KProperty для поля Java, метода или конструктора Java для KFunction и наоборот.
Преобразования SAM
Kotlin поддерживает преобразования SAM для Java и интерфейсов Kotlin. Эта поддержка Java означает, что литералы функций Kotlin могут быть автоматически преобразованы в реализации интерфейсов Java с одним методом без по умолчанию, если типы параметров метода интерфейса соответствуют типам параметров Kotlin-функции.
Вы можете использовать это для создания экземпляров интерфейсов SAM:
val runnable = Runnable { println("This runs in a runnable") }
...и в вызовах методов:
val executor = ThreadPoolExecutor()
// Java signature: void execute(Runnable command)
executor.execute { println("This runs in a thread pool") }
Если класс Java имеет несколько методов, принимающих функциональные интерфейсы, вы можете выбрать нужный метод, используя адаптерную функцию, которая преобразует лямбда-выражение в определённый тип SAM. Эти адаптерные функции также генерируются компилятором при необходимости:
executor.execute(Runnable { println("This runs in a thread pool") })
Использование JNI с Kotlin
Для объявления функции, реализованной в коде нативных языках (C или C++), необходимо пометить её модификатором external:
external fun foo(x: Int): Double
Остальная процедура работает точно так же, как и в Java.
Вы также можете пометить геттеры и сеттеры свойств как external:
var myProperty: String
external get
external set
За кулисами это создаст две функции getMyProperty и setMyProperty, обе помеченные как external.
Использование Lombok-сгенерированных объявлений в Kotlin
Вы можете использовать сгенерированные Lombok объявления Java в коде Kotlin. Если вам нужно сгенерировать и использовать эти объявления в одном смешанном Java/Kotlin модуле, вы можете узнать как это сделать на странице плагина компилятора Lombok. Если вы вызываете такие объявления из другого модуля, тогда вам не нужно использовать этот плагин для компиляции этого модуля.
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/java-interop.html