Как из Kotlin вызывать методы Java и наоборот?
Kotlin и Java полностью совместимы на уровне байткода JVM. Это означает, что Kotlin-код может напрямую вызывать Java-код, а Java-код — Kotlin. Такая интероперабельность — одна из причин популярности Kotlin на Android. Однако при вызовах между языками есть нюансы, связанные с синтаксисом, null-безопасностью, аннотациями и некоторыми языковыми особенностями.
Вызов Java-кода из Kotlin
Kotlin может напрямую вызывать Java-классы, методы, поля, создавать экземпляры классов и использовать стандартные библиотеки Java без необходимости адаптации.
Примеры
Java-класс:
public class JavaUtils {
public static int sum(int a, int b) {
return a + b;
}
public String greet(String name) {
return "Hello, " + name;
}
}
Kotlin-код:
val result = JavaUtils.sum(2, 3) // вызов static-метода
val greeting = JavaUtils().greet("Alex") // вызов instance-метода
Особенности вызова Java из Kotlin
1. Nullability
Kotlin требует указания null-безопасности. Все Java-типы по умолчанию считаются «платформенными» (String!), и Kotlin позволяет обращаться к ним как nullable или non-nullable — на усмотрение разработчика.
val name: String = JavaUtils().greet("Bob") // Kotlin считает, что greet() возвращает String!
Для большей строгости можно использовать аннотации в Java: @Nullable, @NotNull.
2. Геттеры и сеттеры
Java-геттеры/сеттеры работают как свойства в Kotlin:
public class Person {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
val person = Person()
person.name = "John" // setter
val n = person.name // getter
3. Методы со static
Java-методы со static можно вызывать напрямую:
val total = Math.max(10, 20) // вызов статического метода Java
Вызов Kotlin-кода из Java
Когда Kotlin-код вызывается из Java, нужно учитывать некоторые особенности Kotlin-языка, которые не существуют в Java.
Пример Kotlin-класса:
class KotlinHelper {
fun greet(name: String): String = "Hi, $name"
companion object {
fun version() = "1.0"
}
}
Java-вызов:
KotlinHelper helper = new KotlinHelper();
String msg = helper.greet("Sam");
// Обращение к companion object
String v = KotlinHelper.Companion.version();
Упрощение доступа через @JvmStatic:
companion object {
@JvmStatic
fun version() = "1.0"
}
Теперь Java-вызов:
String v = KotlinHelper.version(); // без .Companion
Частые Kotlin-фичи, которые требуют аннотаций или адаптаций для Java
1. Top-level функции
Kotlin-функции вне классов создают скрытый класс с суффиксом Kt.
// File: Utils.kt
fun sayHi() = "Hi"
Java:
String msg = UtilsKt.sayHi();
Чтобы задать имя явно:
@file:JvmName("Utils")
Теперь Java:
String msg = Utils.sayHi();
2. Default arguments
Java не поддерживает параметры по умолчанию. Kotlin решает это через перегрузку с @JvmOverloads.
class Printer {
@JvmOverloads
fun print(text: String, count: Int = 1) {
repeat(count) { println(text) }
}
}
Java:
new Printer().print("Hello"); // 1 раз
new Printer().print("Hello", 3); // 3 раза
3. Extension-функции
Из Java расширения нельзя вызвать напрямую, так как они превращаются в статические методы с передачей объекта как первого параметра.
fun String.hello() = "Hello, $this"
Java:
String msg = MyExtensionsKt.hello("Tom"); // имя файла + имя функции
4. Properties
Kotlin-свойства компилируются в get/set методы. В Java их вызывают как обычные методы:
val name: String = "Alex"
Java:
String n = kotlinClass.getName(); // автоматически сгенерированный геттер
5. Sealed классы
Java может использовать sealed-классы, но у них могут быть ограничения в доступе к наследникам — Java не может объявить собственные подклассы sealed-класса.
Kotlin-аннотации для Java-интероперабельности
-
@JvmStatic — генерирует static-методы.
-
@JvmOverloads — создает перегрузки с параметрами по умолчанию.
-
@JvmField — делает поле доступным напрямую без get/set.
-
@JvmName — задает имя класса или функции для JVM.
-
@JvmMultifileClass — объединяет несколько файлов в один .class.
-
@Throws — указывает, какие исключения выбрасываются функцией.
@Throws(IOException::class)
fun readFile(path: String): String { /\*...\*/ }
Kotlin и Java классы в Android Studio
Android Studio и Gradle поддерживают совместную компиляцию Kotlin и Java: вы можете свободно размещать .kt и .java файлы в одном проекте. Kotlin может использовать Java классы без каких-либо дополнительных действий, а Java может использовать Kotlin при соблюдении описанных выше правил.
Пример смешанного проекта
// KotlinHelper.kt
class KotlinHelper {
fun double(x: Int) = x \* 2
}
// MainActivity.java
KotlinHelper helper = new KotlinHelper();
int value = helper.double(10); // вызов Kotlin-кода из Java
// JavaUtil.java
public class JavaUtil {
public static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
}
val reversed = JavaUtil.reverse("hello") // вызов Java-кода из Kotlin