Spec-Zone.ru › Kotlin 1.6

Вызов 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 для игнорирования несоответствий обработки null

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

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

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

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

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

Все примеры в этом разделе используют аннотации обработки null 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 также учитывает аннотации обработки 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.

Примечание: Если аннотация обработки null поддерживает другие цели, применимые к типу помимо цели 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])
}

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") })

Преобразования 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

Вы можете использовать Java-объявления, сгенерированные Lombok, в Kotlin-коде. Если вам нужно генерировать и использовать эти объявления в одном смешанном Java/Kotlin-модуле, вы можете узнать, как это сделать на странице плагина Lombok для компилятора. Если вы вызываете такие объявления из другого модуля, вам не нужно использовать этот плагин для компиляции этого модуля.

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

© 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

Spec-Zone.ru

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