Mine sisu juurde

Kasutaja:OnlyMarksam/Java Native Interface

Allikas: Vikipeedia
Redaktsioon seisuga 4. november 2018, kell 20:40 kasutajalt OnlyMarksam (arutelu | kaastöö) (OnlyMarksam teisaldas lehekülje Kasutaja:OnlyMarksam/liivakast pealkirja Kasutaja:OnlyMarksam/Java Native Interface alla)

Java Native Interface (JNI) on tarkvararaamistik, mis võimaldab Java virtuaalmasinas (JVM) jooksval Java programmil kutsuda välja operatsioonisüsteemi ja riistvaraspetsiifilisi applikatsioone ning teeke, mis on kirjutatud teistes programmeerimiskeeltes näiteks C, C++ ja Assembler[1]

Eesmärgid

JNI võimaldab programmeerijal lahendada olukorda, kus tarkvara kirjutamine täielikult Javas ei ole võimalik näiteks kui Java standardteek ei toeta platvormispetsiifilist funktsionaalsust või teeki. Samuti aitab JNI taaskasutada varasemalt mõnes muus programmeerimiskeeles kirjutatud teeki. JNI annab programmeerijale ligipääsu süsteemi madalatasemelistele resurssidele näiteks mälu ja I/O operatsioonid, mis teeb programmi kirjutamise keerulisemaks aga samas ka paindlikumaks.[2]

Üldiselt soovitatakse JNI kasutamist võimalikult palju vältida, kuna väliste masinkoodiks kompileeritud teekide kasutamisega muutub rakendus platvormist sõltuvaks. Selle probleemi lahendamiseks tuleb iga platvormi jaoks kompileerida eraldi teek, ning siis lasta Java koodil käivitamise ajal tuvastada kasutaja operatsioonisüsteem ja selle põhjal laadida õige teek.

Kasutamine

Selleks, et defineerida süsteemispetsiifilist (inglise keeles native) funktsiooni tuleb definitsioonis kasutada native võtmesõna. See annab Java kompilaatorile teada, et funktsioon on implementeeritud eraldiseisvas .so/.dll/.dylib (sõltuvalt operatsioonisüsteemist) failis mitte ei ole osa Javas kirjutatud koodist.

public class JniTest {

    private static native int square(int x);

    public static void main(String[] args) {
        System.loadLibrary("jniTest");
        System.out.println(square(20));
    }
}

Nüüd käsureal sisestame javac -h . JniTest.java mis genereerib automaatselt selle klassi põhjal meile järgneva päise faili nimega JniTest.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JniTest */

#ifndef _Included_JniTest
#define _Included_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JniTest
 * Method:    square
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_JniTest_square
  (JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

Implementatsiooni kirjutame faili JniTest.cpp, mis võiks välja näha midagi sellist

#include "JniTest.h"

JNIEXPORT jint JNICALL Java_JniTest_square(JNIEnv *env, jclass thisOpj, jint x) {
    return x * x;
}

Järgmiseks sammuks on C keeles kirjutatud koodi kompileerimine Windowsil käsuga g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 JniTest.cpp -o JniTest.o. Viimaseks sammuks on kompileerimisel tekkinud objektifaili linkimine Windowsil käsuga g++ -shared -o jniTest.dll JniTest.o -Wl,--add-stdcall-alias. Selle tulemusel tekib jniTest.dll fail, mis laetakse Java koodis käsuga System.loadLibrary("jniTest"). Programmi käivitamiseks tuleb määrata JVM parameeter java.library.path, mille väärtuseks määrata .dll faili asukoht.

Tüübid

Tabel näitab soseid Java (JNI) ja C keele tüüpide vahel[3]

C tüüp Java tüüp Kirjeldus
unsigned char jboolean 8 bitti, märgita
signed char jbyte 8 bitti, märgiga
unsigned short jchar 16 bitti, märgita
short jshort 16 bitti, märgiga
long jint 32 bitti, märgiga

long long
__int64

jlong 64 bitti, märgiga
float jfloat 32 bitti
double jdouble 64 bitti
void void N/A

Jõudlus

JNI võib tekitada märkimisväärset jõudluse kadu teatud tingimustel[4]:

  • meetodite ja klassimuutujate korduv küsimine - kuna tüübid programmi töö käigus ei muutu, siis on need võimalik pärast esmakordset küsimist salvestada
  • massiivi üksikute elementide muutmisel sellest täieliku koopia tegemine - JNI võimaldab küsida ainult teatud osa massiivist
  • meetodile objekti andmine parameetriks tähendab seda, et riistvaraspetsiifiline kood peab iga objektimuutuja eraldi küsima JVM käest - parem on anda kõik muutujad meetodile eraldi argumentidena kui ühe objektina
  • kuna JNI meetodi väljakutse võib võtta kuni 5 korda kauem aega kui tavalise meetodi väljakutse, siis on vajalik rakendus disainida selliselt, et iga JNI väljakutsega tehakse ära võimalikult suur hulk tööd

Viited

  1. "Guide to JNI (Java Native Interface)".
  2. "Oracle javadoc".
  3. "Java Fundamentals Tutorial: Java Native Interface (JNI)".
  4. "Best practices for using the Java Native Interface".