Spec-Zone.ru › Kotlin 1.8

Вызов 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 не выдаёт ошибок нулевости во время компиляции, но вызов может завершиться ошибкой во время выполнения из-за исключения NullPointerException или утверждения, которое генерирует Kotlin для предотвращения распространения null:

item.substring(1) // allowed, throws 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 или non-null",

  • Array<(out) T>! означает "массив Java типа T (или подтип T ), nullable или non-null"

Аннотации нулевости

Типы Java, имеющие аннотации нулевости, представляются не как платформенные типы, а как фактические nullable или non-null типы Kotlin. Компилятор поддерживает несколько вариантов аннотаций нулевости, включая:

  • 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)

Вы можете указать, сообщает ли компилятор о несовпадении нулевости на основе информации из конкретных типов аннотаций нулевости. Используйте опцию компилятора -Xnullability-annotations=@<package-name>:<report-level>. В аргументе укажите полностью квалифицированный пакет аннотаций нулевости и один из этих уровней отчёта:

  • ignore для игнорирования несовпадений нулевости

  • warn для вывода предупреждений

  • strict для вывода ошибок.

Полный список поддерживаемых аннотаций нулевости см. в исходном коде компилятора Kotlin.

Аннотирование аргументов и параметров типов

Вы можете аннотировать аргументы и параметры типов дженериков, чтобы также предоставить информацию о нулевости для них.

Все примеры в этом разделе используют аннотации нулевости JetBrains из пакета org.jetbrains.annotations.

Аргументы типов

Рассмотрим эти аннотации в 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 также учитывает аннотации нулевости в аргументах типов базовых классов и интерфейсов. Например, есть два класса 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.

Параметры типов

По умолчанию, нулевость простых параметров типов в Kotlin и Java не определена. В Java вы можете указать её с помощью аннотаций нулевости. Давайте аннотируем параметр типа класса Base:

public class Base<@NotNull T> {}

При наследовании от Base, Kotlin ожидает non-null аргумент или параметр типа. Таким образом, следующий код Kotlin вызывает предупреждение:

class Derived<K> : Base<K> {} // warning: K has undefined nullability

Вы можете исправить это, указав верхнюю границу K : Any.

Kotlin также поддерживает аннотации нулевости в ограничениях параметров типов Java. Давайте добавим ограничения к Base:

public class BaseWithBound<T extends @NotNull Number> {}

Kotlin переводит это следующим образом:

class BaseWithBound<T : Number> {}

Таким образом, передача nullable типа как аргумента или параметра типа вызывает предупреждение.

Аннотирование аргументов и параметров типов работает с Java 8 и более поздними версиями. Функция требует, чтобы аннотации нулевости поддерживали цель TYPE_USE (org.jetbrains.annotations поддерживает это в версии 15 и выше). Используйте опцию компилятора -Xtype-enhancement-improvements-strict-mode для отчёта об ошибках в коде Kotlin, использующем нулевую информацию, отличную от аннотаций нулевости из Java.

Примечание: если аннотация нулевости поддерживает другие цели, применимые к типу помимо цели TYPE_USE, тогда TYPE_USE имеет приоритет. Например, если @Nullable имеет как TYPE_USE, так и METHOD цели, подпись метода Java @Nullable String[] f() станет fun f(): Array<String?>! в Kotlin.

Поддержка 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?
}

Типы в этом примере существуют только при включенном строгом режиме; в противном случае остаются платформенные типы. См. @UnderMigration аннотацию и Настройка компилятора.

Также поддерживается значение по умолчанию допустимости 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, т.е. сообщает об ошибках при некорректном использовании и влияет на типы в аннотированных объявлениях так, как они видны в Kotlin

  • MigrationStatus.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 {}

Статус миграции аннотации допустимости null не наследуется её псевдонимами квалификаторов типов, но применяется к её использованию в квалификаторах типов по умолчанию.

Если квалификатор типа по умолчанию использует псевдоним квалификатора типа, и они оба @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.

Примечание: встроенные аннотации JSR-305 @Nonnull, @Nullable и @CheckForNull всегда включены и влияют на типы аннотированных объявлений в Kotlin независимо от конфигурации компилятора с флагом -Xjsr305.

Например, добавление -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

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.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, чтобы избежать затрат на операции 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])
}

Переменное число аргументов (varargs) Java

Классы 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") })

Преобразования SAM работают только для интерфейсов, а не для абстрактных классов, даже если они также имеют только один абстрактный метод.

Использование 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. Если вы вызываете такие объявления из другого модуля, то вам не нужно использовать этот плагин для компиляции этого модуля.

Последнее изменение: 10 января 2023
Сравнение с Java Вызов Kotlin из Java

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/java-interop.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API