stringtranslate.com

Собственный интерфейс Java

В разработке программного обеспечения Java Native Interface ( JNI ) представляет собой среду программирования интерфейса внешних функций , которая позволяет коду Java , работающему на виртуальной машине Java (JVM), вызывать и вызываться [1] собственными приложениями (программами, специфичными для аппаратного обеспечения и операционной системы ). системная платформа) и библиотеки , написанные на других языках, таких как C , C++ и ассемблер .

Цели

JNI позволяет программистам писать собственные методы для обработки ситуаций, когда приложение не может быть полностью написано на языке программирования Java, например, когда стандартная библиотека классов Java не поддерживает функции, специфичные для платформы, или библиотеку программ. Он также используется для изменения существующего приложения (написанного на другом языке программирования), чтобы оно было доступно приложениям Java. Многие классы стандартной библиотеки зависят от JNI, предоставляющего функциональные возможности разработчику и пользователю, например возможности файлового ввода-вывода и звука. Включение реализаций API, чувствительных к производительности и платформе, в стандартную библиотеку позволяет всем приложениям Java получать доступ к этой функциональности безопасным и независимым от платформы способом.

Платформа JNI позволяет собственному методу использовать объекты Java так же, как эти объекты использует код Java. Собственный метод может создавать объекты Java, а затем проверять и использовать эти объекты для выполнения своих задач. Собственный метод также может проверять и использовать объекты, созданные кодом приложения Java.

Только приложения и подписанные апплеты могут вызывать JNI.

Приложение, использующее JNI, теряет возможности переносимости платформы, которые предлагает Java (частичным обходным решением является написание отдельной реализации кода JNI для каждой платформы, а Java определяет операционную систему и загружает правильную версию во время выполнения).

Не только собственный код может взаимодействовать с Java, но и использовать Java Canvas, что возможно с помощью Java AWT Native Interface . Процесс практически тот же, с небольшими изменениями. Собственный интерфейс Java AWT доступен только начиная с J2SE 1.3.

JNI также обеспечивает прямой доступ к ассемблерному коду , даже не проходя через мост C. [2] Доступ к Java-приложениям из сборки возможен таким же образом. [3]

Дизайн

В среде JNI собственные функции реализуются в отдельных файлах .c или .cpp. (C++ предоставляет немного более простой интерфейс с JNI.) Когда JVM вызывает функцию, она передает JNIEnvуказатель, jobjectуказатель и любые аргументы Java, объявленные методом Java. Например, следующее преобразует строку Java в собственную строку:

extern "C" JNIEXPORT void JNICALL Java_ClassName_MethodName ( JNIEnv * env , jobject obj , jstring javaString ) { const char * nativeString = env -> GetStringUTFChars ( javaString , 0 );                 //Делаем что-нибудь с нативной строкой env -> ReleaseStringUTFChars ( javaString , nativeString ); } 

Указатель env— это структура, содержащая интерфейс для JVM. Он включает в себя все функции, необходимые для взаимодействия с JVM и работы с объектами Java. Примерами функций JNI являются преобразование собственных массивов в/из массивов Java, преобразование собственных строк в/из строк Java, создание экземпляров объектов, выдача исключений и т. д. По сути, все, что может сделать код Java, можно сделать с помощью JNIEnv, хотя и со значительно меньшей легкостью.

Аргумент objпредставляет собой ссылку на объект Java, внутри которого объявлен этот собственный метод.

Собственные типы данных могут быть сопоставлены с типами данных Java или из них. Для составных типов, таких как объекты, массивы и строки , собственный код должен явно преобразовывать данные, вызывая методы в JNIEnv.

Указатель среды JNI ( JNIEnv* ) передается в качестве аргумента для каждой встроенной функции, сопоставленной с методом Java, что позволяет взаимодействовать со средой JNI внутри собственного метода. Этот указатель интерфейса JNI можно сохранить, но он остается действительным только в текущем потоке. Другие потоки должны сначала вызвать AttachCurrentThread() , чтобы подключиться к виртуальной машине и получить указатель интерфейса JNI. После подключения собственный поток работает как обычный поток Java, выполняющийся в собственном методе. Собственный поток остается прикрепленным к виртуальной машине до тех пор, пока он не вызовет DetachCurrentThread() для отсоединения. [4]

Платформа JNI не обеспечивает автоматическую сборку мусора для ресурсов памяти, отличных от JVM, выделяемых кодом, выполняющимся на собственной стороне. Следовательно, собственный код (например, язык ассемблера) берет на себя ответственность за явное освобождение любых таких ресурсов памяти, которые приобретает собственный код.

На платформах Linux и Solaris, если собственный код регистрируется как обработчик сигналов, он может перехватывать сигналы, предназначенные для JVM. Цепочка ответственности может использоваться, чтобы позволить собственному коду лучше взаимодействовать с JVM. На платформах Windows структурированная обработка исключений (SEH) может использоваться для упаковки собственного кода в блоки try/catch SEH, чтобы перехватывать программные прерывания, генерируемые машиной (CPU/FPU) (например, нарушения доступа к нулевому указателю и операции деления на ноль). ), и обрабатывать эти ситуации до того, как прерывание будет передано обратно в JVM (т. е. на сторону Java-кода), что, по всей вероятности, приведет к необработанному исключению. [ оригинальное исследование? ]

Кодировка, используемая для функций NewStringUTF, GetStringUTFLength, GetStringUTFChars, ReleaseStringUTFChars и GetStringUTFRegion, представляет собой «модифицированную UTF-8», [5] которая не является допустимой UTF-8 для всех входных данных, но на самом деле это другая кодировка. Нулевой символ (U+0000) и кодовые точки, не входящие в базовую многоязычную плоскость (больше или равные U+10000, т. е. представленные как суррогатные пары в UTF-16), в модифицированном UTF-8 кодируются по-разному. Многие программы на самом деле используют эти функции неправильно и обрабатывают строки UTF-8, возвращаемые или передаваемые в функции, как стандартные строки UTF-8, а не модифицированные строки UTF-8. Программы должны использовать функции NewString, GetStringLength, GetStringChars, ReleaseStringChars, GetStringRegion, GetStringCritical и ReleaseStringCritical, которые используют кодировку UTF-16LE в архитектурах с прямым порядком байтов и UTF-16BE в архитектурах с прямым порядком байтов, а затем использовать кодировку от UTF-16 до UTF- 8 процедур преобразования. [ оригинальное исследование? ]

Типы сопоставления

В следующей таблице показано сопоставление типов между Java (JNI) и машинным кодом.

Кроме того, подпись "L fully-qualified-class ;"будет означать класс, однозначно определенный этим именем; например, подпись "Ljava/lang/String;"относится к классу java.lang.String. Кроме того, добавление префикса [к подписи создает массив этого типа; например, [Iозначает тип массива int. Наконец, voidподпись использует Vкод.

Эти типы взаимозаменяемы. Можно использовать jintтам, где вы обычно используете int, и наоборот, без необходимости приведения типов . Однако сопоставление строк и массивов Java с собственными строками и массивами отличается. Если a jstringиспользуется вместо a char *, код может привести к сбою JVM. [ оригинальное исследование? ]

Производительность

JNI несет значительные накладные расходы и потерю производительности при определенных обстоятельствах: [6]

Альтернативы

Собственная реализация виртуальной машины Java от Microsoft ( Visual J++ ) имела аналогичный механизм для вызова собственного кода Java, называемый Raw Native Interface ( RNI ). Кроме того, у него был простой способ вызова существующего собственного кода, который сам не знал о Java, такого как (но не ограничиваясь) Windows API, называемый J/Direct . Однако после судебного разбирательства между Sun и Microsoft по поводу этой реализации Visual J++ больше не поддерживается.

RNI был менее неуклюжим в использовании, чем JNI, поскольку не требовалось никакого учета указателя среды Java. Вместо этого ко всем объектам Java можно было получить прямой доступ. Чтобы облегчить это, использовался инструмент, который генерировал файлы заголовков из классов Java. Точно так же J/Direct было проще использовать, чем использовать необходимую промежуточную собственную библиотеку и JNI.

Java Native Access (JNA) — это разработанная сообществом библиотека, которая предоставляет Java-программистам легкий доступ к собственным общим библиотекам без использования JNI. Однако для этого требуется перераспределение зависимой библиотеки jar. Компромисс заключается в том, что JNI сложнее кодировать, а JNA медленнее. [7] JNI встроен в ядро ​​Java.

Смотрите также

Рекомендации

  1. ^ «Обзор собственного интерфейса Java» . Руководство и спецификация для программиста собственного интерфейса Java . Проверено 27 декабря 2018 г.
  2. ^ «Вызов программ на языке ассемблера из Java». Java.net. 19 октября 2006 г. Архивировано из оригинала 30 марта 2008 г. Проверено 6 октября 2007 г.
  3. ^ «Запуск приложений Java из программ на языке ассемблера» . Java.net. 19 октября 2006 г. Архивировано из оригинала 11 октября 2007 г. Проверено 4 октября 2007 г.
  4. ^ API вызова. Сан Микросистемс. https://docs.oracle.com/en/java/javase/11/docs/specs/jni/invocase.html
  5. ^ «Типы JNI и структуры данных».
  6. ^ «Java — Что делает вызовы JNI медленными? - Переполнение стека» .
  7. ^ Закусило, Александр. «Github также является оригинальным источником JNA. Тесты скорости тестов JNA и JNI». Гитхаб . Гитхаб . Проверено 30 марта 2023 г.

Библиография

Внешние ссылки