[java] Использовать JNI вместо JNA для вызова собственного кода?



Answers

Трудно ответить на такой общий вопрос. Я полагаю, что наиболее очевидным отличием является то, что с JNI преобразование типов реализовано на родной стороне Java / родной границы, а с JNA преобразование типов реализовано на Java. Если вы уже чувствуете себя вполне комфортно с программированием на C и должны сами реализовать собственный код, я бы предположил, что JNI не будет казаться слишком сложным. Если вы программист на Java и вам нужно только вызывать стороннюю библиотеку, использование JNA, вероятно, является самым простым путем, чтобы избежать, возможно, не столь очевидных проблем с JNI.

Хотя я никогда не сравнивал какие-либо различия, я бы из-за дизайна, по крайней мере, предположил, что преобразование типа с JNA в некоторых ситуациях будет хуже, чем с JNI. Например, при передаче массивов JNA будет преобразовывать их из Java в native в начале каждого вызова функции и обратно в конце вызова функции. С JNI вы можете управлять собой, когда генерируется собственное «представление» массива, потенциально только создавая представление о части массива, сохраняя представление по нескольким вызовам функций и в конце релиза представления и решая, хотите ли вы сохранить изменения (возможно, потребовать, чтобы скопировать данные назад) или отказаться от изменений (без необходимости копирования). Я знаю, что вы можете использовать собственный массив для вызовов функций с помощью JNA с использованием класса памяти, но для этого также потребуется копирование памяти, что может быть ненужным с JNI. Разница может быть неактуальной, но если ваша первоначальная цель - увеличить производительность приложения, реализовав ее части в собственном коде, использование хуже используемой мостовой технологии, по-видимому, не является самым очевидным выбором.

Question

JNA кажется более легким в использовании для вызова собственного кода по сравнению с JNI. В каких случаях вы бы использовали JNI над JNA?




Если вам нужна производительность JNI, но ее сложно устранить, вы можете использовать инструменты, которые автоматически создают привязки JNI. Например, JANET (отказ от ответственности: я написал его) позволяет смешивать Java и C ++-код в одном исходном файле и, например, совершать вызовы с C ++ на Java с использованием стандартного синтаксиса Java. Например, вот как вы должны напечатать строку C для стандартного вывода Java:

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

Затем JANET переводит внедренную в обратную сторону Java в соответствующие вызовы JNI.




Если я что-то не хватает, не главное отличие JNA от JNI от того, что с JNA вы не можете вызывать код Java из native (C) кода?




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




Links