- JNI — это встроенный интерфейс, который позволяет коду JVM вызывать собственные функции на C или C++, а также позволяет собственному коду вызывать Java-код.
- Метод
nativeне имеет тела Java; JVM связывает его со скомпилированной функцией во время выполнения. - Программы используют его для повторного использования собственных библиотек, доступа к операционной системе, ускорения часто используемых участков кода или взаимодействия с оборудованием.
- Граница чёткая: сбои в собственном коде могут привести к падению JVM, а сборки собственного кода зависят от платформы.
JNI — это Java Native Interface, встроенная часть Java, которая позволяет коду, работающему на JVM, вызывать функции, написанные на C или C++, и позволяет этому нативному коду вызывать методы обратно в Java. Именно так программа на Java выходит за пределы JVM для использования платформенной библиотеки или фрагмента скомпилированного машинного кода.
Где используется Opal
Opal — это мод для Fabric, поэтому большая его часть написана на обычном Java, а скрипты выполняются на JavaScript, а не на нативном коде. Если вы только начинаете, обратитесь к руководству по настройке.
Что делает JNI
JNI соединяет два мира: управляемый Java-код на JVM и нативный код, скомпилированный в машинные инструкции. Метод Java помечается как native и не имеет тела в Java. Во время выполнения JVM загружает нативную библиотеку и связывает этот метод с соответствующей функцией на C или C++. Затем обе стороны передают аргументы и возвращают значения друг другу.
Нативная сторона получает указатель JNIEnv. Этот дескриптор является шлюзом: он предоставляет функции для чтения полей Java, вызова методов Java, создания объектов и выбрасывания исключений. Таким образом, мост работает в обе стороны, а не только Java, обращающаяся наружу.
Почему программа использует JNI
Большинству Java-кода JNI не требуется. Программа обращается к нему в нескольких ситуациях:
- Повторное использование существующего нативного кода. Зрелая библиотека на C или C++ уже выполняет задачу, и переписывание её на Java не стоит усилий.
- Доступ к операционной системе. Некоторые функции платформы не имеют чисто Java API, поэтому нативный вызов — единственный способ.
- Ускорение критического участка кода. Тесная числовая или низкоуровневая рутина может работать быстрее в виде скомпилированного нативного кода, чем на JVM.
- Взаимодействие с оборудованием или драйверами. Графика, аудио и доступ к устройствам часто скрыты за нативными библиотеками.
Как работает вызов JNI
Шаги одинаковы на каждой платформе.
| Шаг | Что происходит |
|---|---|
| Объявление | Метод Java объявляется с ключевым словом native и без тела. |
| Сборка | Функция C или C++ компилируется в общую библиотеку (.dll, .so, .dylib). |
| Загрузка | Java вызывает System.loadLibrary для загрузки этой библиотеки во время выполнения. |
| Связывание | JVM сопоставляет метод native с функцией C по имени. |
| Вызов | Java вызывает метод; управление передается в нативный код и обратно. |
Имена функций следуют фиксированному шаблону, чтобы JVM могла их найти, а сгенерированный заголовочный файл сообщает вам точный сигнатур для реализации.
Затраты и риски
JNI — мощный инструмент, но у него есть острые углы. Сбой в нативном коде может привести к падению всей JVM, поскольку этот код выполняется за пределами защитной сети JVM. Память, выделенная нативной стороной, не собирается мусором, поэтому утечки легко возникают. Каждое пересечение между Java и нативным кодом имеет накладные расходы, поэтому вызов через границу в плотном цикле может быть медленным. И нативные библиотеки специфичны для платформы: сборка для Windows не будет работать в Linux без отдельной компиляции.
Используйте экономно
Поскольку нативная граница обходит гарантии безопасности JVM, JNI — это тот инструмент, к которому прибегают только тогда, когда нет чистого Java-пути. Большинство модов, включая Opal, не нуждаются в нём.
Часто задаваемые вопросы
Да. JNI поставляется вместе с JDK и JVM. Вам не нужно устанавливать ничего дополнительно на стороне Java, хотя для компиляции части на C или C++ вам потребуется нативный инструментарий.
Нет. Java-часть остается переносимой, но нативный код компилируется для одной операционной системы и процессора, поэтому вам потребуется отдельная нативная сборка для каждой платформы.
Нет. Это оригинальный, встроенный способ. Более новые версии Java добавляют более современный API для вызова функций извне, который призван быть более безопасным и простым, но JNI по-прежнему широко используется и хорошо понятен.
Клиент, написанный в основном на Java, иногда нуждается в нативной библиотеке для выполнения задачи, которую JVM не может выполнить напрямую. JNI — это стандартный мост для загрузки и вызова этой библиотеки.