Вызов кода 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, при вызове из Kotlin он вернёт Unit. Если кто-то, по какой-то причине, использует это возвращаемое значение, оно будет присвоено в месте вызова компилятором 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 не выдаёт ошибок неполноты при компиляции, но вызов может завершиться ошибкой во время выполнения из-за исключения NullPointerException или утверждения, которое 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) - 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).
Полный список можно найти в исходном коде компилятора Kotlin.
Аннотирование параметров типа
Возможно аннотирование аргументов типа для общих типов, чтобы предоставить информацию о возможности наличия null для них. Например, рассмотрим эти аннотации в объявлении Java:
@NotNull
Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements) { ... }
Это приводит к следующей сигнатуре в Kotlin:
fun toSet(elements: (Mutable)Collection<String>) : (Mutable)Set<String> { ... }
Обратите внимание на аннотации @NotNull на аргументах типа String. Без них мы получаем платформенные типы в аргументах типа:
fun toSet(elements: (Mutable)Collection<String!>) : (Mutable)Set<String!> { ... }
Аннотирование аргументов типа работает с целевой версией Java 8 или выше и требует поддержки аннотаций для обработки null в целевой версии TYPE_USE (org.jetbrains.annotations поддерживает это в версии 15 и выше).
Примечание: из-за текущих технических ограничений IDE некорректно распознаёт эти аннотации на аргументах типа в скомпилированных библиотеках Java, которые используются как зависимости.
Поддержка JSR-305
Аннотация @Nonnull, определённая в JSR-305, поддерживается для обозначения возможности наличия null для типов Java.
Если значение @Nonnull(when = ...) равно When.ALWAYS, аннотированный тип рассматривается как non-null; When.MAYBE и When.NEVER обозначают nullable тип; и When.UNKNOWN принудительно делает тип платформенным.
Библиотека может быть скомпилирована с аннотациями JSR-305, но нет необходимости делать артефакт аннотаций (например, jsr305.jar ) зависимостью от компиляции для потребителей библиотеки. Компилятор Kotlin может читать аннотации JSR-305 из библиотеки без наличия аннотаций в пути к классу.
Начиная с Kotlin 1.1.50, также поддерживаются пользовательские квалификаторы для обработки null (KEEP-79) (см. ниже).
Псевдонимы квалификаторов типа (начиная с 1.1.50)
Если тип аннотации помечен как @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!`
}
Значения по умолчанию для квалификаторов типа (начиная с 1.1.50)
@TypeQualifierDefault позволяет вводить аннотации, которые при применении определяют значение по умолчанию для обработки null в пределах аннотированного элемента.
Такой тип аннотации сам должен быть помечен аннотациями @Nonnull (или её псевдонимом) и @TypeQualifierDefault(...) с одним или несколькими значениями ElementType:
-
ElementType.METHODдля типов возвращаемых методов; -
ElementType.PARAMETERдля параметров значений; -
ElementType.FIELDдля полей; и -
ElementType.TYPE_USE(начиная с 1.1.60) для любых типов, включая аргументы типа, верхние границы параметров типа и wildcard-типы.
Значение по умолчанию для обработки 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?
}
Примечание: типы в этом примере действуют только при включённом строгом режиме, в противном случае остаются платформенные типы. См. раздел аннотации
@UnderMigrationи раздел Конфигурация компилятора.
Также поддерживается значение по умолчанию для обработки null на уровне пакета:
// FILE: test/package-info.java @NonNullApi // declaring all types in package 'test' as non-nullable by default package test;
Аннотация @UnderMigration (начиная с 1.1.60)
Аннотация @UnderMigration (предоставляемая в отдельном артефакте kotlin-annotations-jvm ) может использоваться авторами библиотек для определения статуса миграции квалификаторов типа для обработки null.
Значение статуса в @UnderMigration(status = ...) определяет, как компилятор обрабатывает некорректное использование аннотированных типов в Kotlin (например, использование значения типа, аннотированного @MyNullable, как не-null):
-
MigrationStatus.STRICTзаставляет аннотацию работать как любая обычная аннотация нуллируемости, т.е. сообщать об ошибках при некорректном использовании и влиять на типы в аннотированных объявлениях так, как они видны в Kotlin; -
при использовании
MigrationStatus.WARN, некорректное использование сообщается как предупреждение при компиляции вместо ошибки, но типы в аннотированных объявлениях остаются платформами; и -
MigrationStatus.IGNOREзаставляет компилятор полностью игнорировать аннотацию нуллируемости.
Поддерживающий библиотеку может добавить статус @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. Пользователи, возможно, захотят плавно мигрировать при обновлении до версии Kotlin, содержащей поддержку JSR-305, так как пользовательские квалификаторы нуллируемости, особенно@TypeQualifierDefault, уже распространены среди многих известных библиотек. Начиная с Kotlin 1.1.60, этот флаг влияет только на аннотации, не являющиеся@UnderMigration. -
-Xjsr305=under-migration:{strict|warn|ignore}(с 1.1.60) для переопределения поведения для аннотаций@UnderMigration. У пользователей может быть разное представление о статусе миграции для библиотек: они могут захотеть иметь ошибки, в то время как официальный статус миграцииWARN, или наоборот, они могут отложить сообщения об ошибках для некоторых до завершения миграции. -
-Xjsr305=@<fq.name>:{strict|warn|ignore}(с 1.1.60) для переопределения поведения для одной аннотации, где<fq.name>— полное имя класса аннотации. Может появляться несколько раз для разных аннотаций. Это полезно для управления состоянием миграции для конкретной библиотеки.
Значения strict, warn и ignore имеют такое же значение, что и значения MigrationStatus, и только режим strict влияет на типы в аннотированных объявлениях, как они видны в Kotlin.
Примечание: встроенные аннотации JSR-305
@Nonnull,@Nullableи@CheckForNullвсегда включены и влияют на типы аннотированных объявлений в Kotlin, независимо от конфигурации компилятора с флагом-Xjsr305.
Например, добавление -Xjsr305=ignore -Xjsr305=under-migration:ignore -Xjsr305=@org.library.MyNullable:warn к аргументам компилятора заставляет компилятор генерировать предупреждения о некорректном использовании типов, аннотированных @org.library.MyNullable, и игнорировать все остальные аннотации JSR-305.
Для версий kotlin 1.1.50+/1.2 значение по умолчанию аналогично -Xjsr305=warn. Значение strict следует рассматривать как экспериментальное (в него могут быть добавлены дополнительные проверки в будущем).
Сопоставленные типы
Kotlin особым образом обрабатывает некоторые типы Java. Такие типы не загружаются из Java «как есть», а сопоставляются с соответствующими типами Kotlin. Сопоставление имеет значение только во время компиляции, представление во время выполнения остается неизменным. Примитивные типы Java сопоставляются с соответствующими типами Kotlin (с учетом платформенных типов):
| Тип Java | Тип Kotlin |
|---|---|
byte | kotlin.Byte |
short | kotlin.Short |
int | kotlin.Int |
long | kotlin.Long |
char | kotlin.Char |
float | kotlin.Float |
double | kotlin.Double |
boolean | kotlin.Boolean |
Некоторые встроенные классы, не являющиеся примитивными, также сопоставляются:
| Тип Java | Тип Kotlin |
|---|---|
java.lang.Object | kotlin.Any! |
java.lang.Cloneable | kotlin.Cloneable! |
java.lang.Comparable | kotlin.Comparable! |
java.lang.Enum | kotlin.Enum! |
java.lang.Annotation | kotlin.Annotation! |
java.lang.CharSequence | kotlin.CharSequence! |
java.lang.String | kotlin.String! |
java.lang.Number | kotlin.Number! |
java.lang.Throwable | kotlin.Throwable! |
Упакованные примитивные типы Java сопоставляются с не-null типами Kotlin:
| Тип Java | Тип Kotlin |
|---|---|
java.lang.Byte | kotlin.Byte? |
java.lang.Short | kotlin.Short? |
java.lang.Integer | kotlin.Int? |
java.lang.Long | kotlin.Long? |
java.lang.Character | kotlin.Char? |
java.lang.Float | kotlin.Float? |
java.lang.Double | kotlin.Double? |
java.lang.Boolean | kotlin.Boolean? |
Обратите внимание, что упакованный примитивный тип, используемый в качестве параметра типа, сопоставляется с платформенным типом: например, List<java.lang.Integer> становится List<Int!> в Kotlin.
Типы коллекций могут быть неизменяемыми или изменяемыми в Kotlin, поэтому коллекции Java сопоставляются следующим образом (все типы Kotlin в этой таблице находятся в пакете kotlin.collections):
| Тип Java | Тип Kotlin (только чтение) | Тип Kotlin (изменяемый) | Тип загрузки платформы |
|---|---|---|---|
Iterator<T> | Iterator<T> | MutableIterator<T> | (Mutable)Iterator<T>! |
Iterable<T> | Iterable<T> | MutableIterable<T> | (Mutable)Iterable<T>! |
Collection<T> | Collection<T> | MutableCollection<T> | (Mutable)Collection<T>! |
Set<T> | Set<T> | MutableSet<T> | (Mutable)Set<T>! |
List<T> | List<T> | MutableList<T> | (Mutable)List<T>! |
ListIterator<T> | ListIterator<T> | MutableListIterator<T> | (Mutable)ListIterator<T>! |
Map<K, V> | Map<K, V> | MutableMap<K, V> | (Mutable)Map<K, V>! |
Map.Entry<K, V> | Map.Entry<K, V> | MutableMap.MutableEntry<K,V> | (Mutable)Map.(Mutable)Entry<K, V>! |
Массивы Java отображаются, как указано ниже:
| Тип Java | Тип Kotlin |
|---|---|
int[] | kotlin.IntArray! |
String[] | kotlin.Array<(out) String>! |
Примечание: статические члены этих типов Java не могут быть непосредственно доступны в объектах-компаньонах типов Kotlin. Чтобы вызвать их, используйте полные квалифицированные имена типов Java, например, java.lang.Integer.toHexString(foo).
Обобщения 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, чтобы избежать затрат на операции преобразования/распаковки. Поскольку 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)
В настоящее время невозможно передать null методу, объявленному как varargs.
Операторы
Поскольку в 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
Приведённый выше код использует связанную ссылку на класс, которая поддерживается начиная с Kotlin 1.1. Вы также можете использовать расширяющее свойство javaClass:
val fooClass = foo.javaClass
clone()
Для переопределения clone() ваш класс должен расширять kotlin.Cloneable:
class Example : Cloneable {
override fun clone(): Any { ... }
}
Не забудьте про Effective Java, 3rd Edition, пункт 13: Переопределите clone обдуманно.
finalize()
Чтобы переопределить finalize() , вам нужно просто его объявить, не используя ключевое слово override:
class C {
protected fun finalize() {
// finalization logic
}
}
Согласно правилам Java, finalize() не может быть private.
Наследование от классов Java
В качестве супертипа для класса Kotlin может быть максимум один класс Java (и столько интерфейсов Java, сколько вам нужно).
Доступ к статическим членам
Статические члены классов 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::class.javaObjectType для получения обёртки примитивных типов.
Другие поддерживаемые случаи включают получение метода Java getter/setter или вспомогательного поля для свойства 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") })
Преобразования SAM работают только для интерфейсов, а не для абстрактных классов, даже если они также имеют только один абстрактный метод.
Использование JNI с Kotlin
Чтобы объявить функцию, реализованную в коде нативных языках (C или C++), необходимо пометить её модификатором external.
external fun foo(x: Int): Double
Остальная часть процедуры работает точно так же, как и в Java.
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/java-interop.html