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

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

Цели

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

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

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

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

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

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

Дизайн

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

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

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

Аргумент объект ссылка на объект 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-16. 8 процедура преобразования.[оригинальное исследование? ]

Типы картографии

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

Тип CТип языка JavaОписаниеПодпись типа
беззнаковый символjbooleanбеззнаковые 8 битZ
подписанный символjbyteподписанный 8 битB
беззнаковый короткийjcharбеззнаковые 16 битC
короткаяjshortподписанные 16 битS
длинныйджинтподписанный 32 битая

долго долго
__int64

jlongподписанные 64 битаJ
плаватьjfloat32 битF
двойнойjdouble64 битD
пустотаV

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

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

Спектакль

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

  • Вызов функций для методов JNI стоит дорого, особенно при повторном вызове метода.
  • Собственные методы не встроены JVM, и этот метод не может быть JIT скомпилирован, поскольку метод уже скомпилирован.
  • Массив Java может быть скопирован для доступа в машинном коде, а затем скопирован обратно. Стоимость может быть линейной в зависимости от размера массива.
  • Если методу передается объект или ему необходимо выполнить обратный вызов, то собственный метод, скорее всего, будет делать свои собственные вызовы JVM. Для доступа к полям, методам и типам Java из собственного кода требуется нечто похожее на отражение. Сигнатуры указываются в строках и запрашиваются из JVM. Это и медленно, и подвержено ошибкам.
  • Строки Java являются объектами, имеют длину и закодированы. Для доступа или создания строки может потребоваться O (n) копия.

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

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

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

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

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

  1. ^ «Обзор собственного интерфейса Java». Руководство программиста и спецификация собственного интерфейса Java. Получено 2018-12-27.
  2. ^ «Вызов программ на языке ассемблера из Java». Java.net. 2006-10-19. Архивировано из оригинал на 2008-03-30. Получено 2007-10-06.
  3. ^ «Запуск приложений Java из программ на языке ассемблера». Java.net. 2006-10-19. Архивировано из оригинал на 2007-10-11. Получено 2007-10-04.
  4. ^ API вызова. Sun Microsystems. https://docs.oracle.com/en/java/javase/11/docs/specs/jni/invocation.html
  5. ^ «Типы JNI и структуры данных».
  6. ^ "java - Что замедляет вызовы JNI? - Переполнение стека".

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

внешняя ссылка