Kotlin не живёт в вакууме: зачем и как дружить с другими языками
Представьте: вы пишете на Kotlin — современном, лаконичном и безопасном языке. Но ваш проект — это не чистый лист. Где-то в недрах системы живёт legacy-код на Java, аналитикам нужна библиотека на Python, а для низкоуровневых операций требуется C. Или вы хотите переиспользовать бизнес-логику на фронтенде, написав её на Kotlin, но там правит бал JavaScript.
Хорошая новость: интеграция Kotlin с другими языками — это не боль, а суперсила. Kotlin спроектирован так, чтобы быть «языком-клеем». Он умеет работать на JVM (рядом с Java), компилироваться в нативный код (Kotlin/Native) и даже в JavaScript (Kotlin/JS).
В этой статье мы разберём четыре ключевых сценария взаимодействия Kotlin с другими языками на практических примерах. Вы узнаете, как вызывать Python из Kotlin, встраивать C-код через JNI, бесшовно работать с Java и даже использовать Kotlin на фронтенде. Поехали!
1. Kotlin и Java: родственная душа с первых строк
Самый очевидный и простой сценарий — Kotlin Java взаимодействие. Поскольку Kotlin компилируется в байт-код JVM, он на 100% совместим с Java. Вы можете вызывать любой Java-код из Kotlin и наоборот — без мостов, адаптеров и боли.
Как вызвать Java из Kotlin
Допустим, у вас есть старый Java-класс для работы с датами:
// Java: DateUtils.java
public class DateUtils {
public static String formatDate(long timestamp) {
return new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date(timestamp));
}
}
В Kotlin вы используете его как родной:
// Kotlin
fun main() {
val formatted = DateUtils.formatDate(System.currentTimeMillis())
println("Сегодня: $formatted") // Сегодня: 2025-04-03
}
Всё работает «из коробки». Но есть нюансы: null-безопасность. Java не знает про nullable-типы Kotlin, поэтому при вызове Java-методов Kotlin трактует возвращаемые значения как платформенные типы (например, String!). Совет: всегда явно указывайте тип или используйте !! / ?. с умом.
Как вызвать Kotlin из Java
Обратная совместимость тоже есть. Предположим, у вас есть Kotlin-файл:
// Kotlin: Calculator.kt
package utils
object Calculator {
@JvmStatic
fun sum(a: Int, b: Int): Int = a + b
}
Из Java вызываем так:
// Java
import utils.Calculator;
public class Main {
public static void main(String[] args) {
int result = Calculator.sum(5, 3);
System.out.println(result); // 8
}
}
Главное — не забыть аннотацию @JvmStatic для статических методов и @JvmName для разрешения конфликтов имён. Интеграция Kotlin с Java настолько плотная, что вы можете смешивать оба языка в одном проекте — это стандарт для Android-разработки и многих бэкендов на Spring.
2. Kotlin и Python: два мира, одна JVM (и GraalVM)
А вот это уже интереснее. Kotlin Python — не самая тривиальная связка, но она возможна. Прямого нативного моста нет, но мы можем использовать JVM-решения.
Вариант A: GraalVM — запускаем Python на JVM
GraalVM — это виртуальная машина, которая умеет запускать несколько языков (Java, Kotlin, JavaScript, Python, Ruby) в одном процессе. Это идеальный инструмент для интеграции Kotlin с Python.
Установите GraalVM и добавьте поддержку Python:
gu install python
Теперь в Kotlin-коде можно вызывать Python-функции:
// Kotlin (GraalVM Polyglot API)
import org.graalvm.polyglot.*
fun main() {
val context = Context.create("python")
// Выполняем Python-код
context.eval("python", """
import math
def calculate_hypotenuse(a, b):
return math.sqrt(a*a + b*b)
""".trimIndent())
// Вызываем функцию из Kotlin
val result = context.getBindings("python")
.getMember("calculate_hypotenuse")
.execute(3, 4)
.asInt()
println("Гипотенуза: $result") // 5
}
Это мощно: вы можете использовать любую Python-библиотеку (например, NumPy или Pandas) прямо из Kotlin. Минус — GraalVM не всегда стабильна с Python, и производительность может быть ниже, чем у родного CPython.
Вариант B: Вызов Python через системный процесс
Простой, но надёжный способ — запустить Python-скрипт как внешний процесс и обменяться данными через JSON или stdin/stdout:
// Kotlin: запускаем Python и получаем результат
import java.io.File
fun callPythonScript(scriptPath: String, input: String): String {
val process = ProcessBuilder("python3", scriptPath)
.redirectErrorStream(true)
.start()
process.outputStream.bufferedWriter().use { writer ->
writer.write(input)
writer.flush()
}
return process.inputStream.bufferedReader().readText()
}
fun main() {
val result = callPythonScript("analyze.py", "Kotlin is awesome!")
println("Python сказал: $result")
}
Этот подход универсален и не требует дополнительных инструментов. Вызов Python из Kotlin через подпроцессы — хороший выбор для микросервисной архитектуры.
3. Kotlin и C/C++: уходим в низкоуровневый код через JNI
Когда нужна работа с железом, графикой или legacy-библиотеками на C, на помощь приходит Kotlin C JNI. JNI (Java Native Interface) — стандартный механизм для вызова нативного кода из JVM. Kotlin здесь ничем не отличается от Java.
Пример: вызываем функцию на C из Kotlin
Сначала пишем C-код:
// native.c
#include <jni.h>
#include <stdio.h>
JNIEXPORT jstring JNICALL
Java_com_example_NativeLib_sayHello(JNIEnv *env, jobject obj, jstring name) {
const char *nativeName = (*env)->GetStringUTFChars(env, name, 0);
char buffer[256];
sprintf(buffer, "Привет, %s! Я C-код.", nativeName);
(*env)->ReleaseStringUTFChars(env, name, nativeName);
return (*env)->NewStringUTF(env, buffer);
}
Компилируем в динамическую библиотеку:
gcc -shared -fpic -o libnative.so -I"$JAVA