Вызов 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, компилятор сгенерирует утверждение при присвоении. Это предотвращает то, чтобы переменные Kotlin non-null содержали 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 |
Тип Kotlin |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Упакованные примитивные типы Java сопоставляются с допускающими NULL типами Kotlin:
Тип Java |
Тип Kotlin |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Обратите внимание, что упакованный примитивный тип, используемый в качестве параметра типа, сопоставляется с платформенным типом: например, List<java.lang.Integer> становится List<Int!> в Kotlin.
Типы коллекций могут быть только для чтения или изменяемыми в Kotlin, поэтому коллекции Java сопоставляются следующим образом (все типы Kotlin в этой таблице находятся в пакете kotlin.collections) :
Тип Java |
Тип Kotlin (только для чтения) |
Изменяемый тип Kotlin |
Загруженный платформенный тип |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Массивы Java сопоставляются, как указано ниже:
Тип Java |
Тип Kotlin |
|---|---|
|
|
|
|
Обобщения 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...
}
}
В этом случае вам нужно использовать оператор распространения * для передачи 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
Вы можете использовать Java-объявления, сгенерированные Lombok, в 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