Java -alkuperäinen käyttöliittymä - Java Native Interface

In ohjelmistojen suunnittelu , The Java Native Interface ( JNI ) on ulkomainen toiminto rajapintana ohjelmoinnin puitteissa , jonka avulla Java- koodin käytössä jossakin Java-virtuaalikone (JVM) soittaa ja kutsuttavaksi natiiveja ohjelmia (ohjelmat erityisesti laitteiston ja käyttöjärjestelmän Platform) ja kirjastot, jotka on kirjoitettu muilla kielillä, kuten C , C ++ ja assembly .

Tavoitteet

JNI avulla ohjelmoijat kirjoittaa kotoisin menetelmiä käsitellä tilanteita, kun sovellus ei voida kirjoitettu kokonaan Java-ohjelmointikielellä, esim standardin Java -luokan kirjastossa ei tue lavan erityispiirteet tai ohjelman kirjastoon. Sitä käytetään myös muokkaamaan olemassa olevaa (toisella ohjelmointikielellä kirjoitettua) sovellusta Java -sovellusten käytettäväksi. Monet kirjaston vakioluokista ovat riippuvaisia ​​JNI: stä tarjotakseen kehittäjälle ja käyttäjälle toiminnallisuutta, esim. Tiedoston I/O ja äänitoiminnot. Suorituskyky- ja käyttöympäristöherkkien sovellusliittymien sisällyttäminen vakiokirjastoon sallii kaikkien Java-sovellusten käyttää tätä toimintoa turvallisesti ja alustasta riippumatta.

JNI -kehyksen avulla alkuperäinen menetelmä voi käyttää Java -objekteja samalla tavalla kuin Java -koodi käyttää näitä objekteja. Alkuperäinen menetelmä voi luoda Java -objekteja ja sitten tarkastella ja käyttää näitä objekteja tehtäviensä suorittamiseen. Alkuperäinen menetelmä voi myös tarkastella ja käyttää Java -sovelluskoodin luomia objekteja.

Vain sovellukset ja allekirjoitetut appletit voivat kutsua JNI: tä.

Sovellus, joka perustuu JNI: hen, menettää Java -alustan siirrettävyyden (osittainen kiertotapa on kirjoittaa erillinen JNI -koodin toteutus kullekin alustalle ja saada Java tunnistamaan käyttöjärjestelmä ja lataamaan oikea ajon aikana).

Natiivikoodin käyttöliittymä ei voi olla vain Java -käyttöliittymä, vaan se voi hyödyntää myös Java -ohjelmaa Canvas, mikä on mahdollista Java AWT -käyttöliittymän avulla . Prosessi on melkein sama, vain muutamilla muutoksilla. Java AWT Native Interface on käytettävissä vain J2SE 1.3: n jälkeen.

JNI mahdollistaa myös suoran pääsyn kokoonpanokoodiin ilman C -siltaa. Java -sovellusten käyttö kokoonpanosta on mahdollista samalla tavalla.

Design

JNI -kehyksessä natiivitoiminnot toteutetaan erillisissä .c- tai .cpp -tiedostoissa. (C ++ tarjoaa hieman yksinkertaisemman käyttöliittymän JNI: n kanssa.) Kun JVM kutsuu funktion, se välittää JNIEnvosoittimen, jobjectosoittimen ja kaikki Java -menetelmän ilmoittamat Java -argumentit. Esimerkiksi seuraava muuntaa Java -merkkijonon natiiviksi merkkijonoksi:

extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
  (JNIEnv *env, jobject obj, jstring javaString)
{
    const char *nativeString = env->GetStringUTFChars(javaString, 0);

    //Do something with the nativeString

    env->ReleaseStringUTFChars(javaString, nativeString);
}

envOsoitin on rakenne, joka sisältää rajapinnan JVM. Se sisältää kaikki toiminnot, joita tarvitaan vuorovaikutukseen JVM: n ja Java -objektien kanssa. Esimerkki JNI -toiminnoista ovat natiivimatriisien muuntaminen Java -matriiseiksi/Java -matriiseiksi, natiivien merkkijonojen muuntaminen Java -merkkijonoiksi/-jonoiksi, objektien näyttäminen, poikkeusten heittäminen jne. Periaatteessa kaikki, mitä Java -koodi voi tehdä, voidaan tehdä käyttämällä JNIEnv, vaikkakin huomattavasti vähemmän helposti.

Argumentti objviittaa Java -objektiin, jonka sisällä tämä alkuperäinen menetelmä on ilmoitettu.

Alkuperäiset tietotyypit voidaan yhdistää Java -tietotyyppeihin tai niistä. Yhdistetyypeille, kuten objekteille, matriiseille ja merkkijonoille , alkuperäisen koodin on nimenomaisesti muunnettava tiedot kutsumalla menetelmiä JNIEnv.

JNI -ympäristön osoitin ( JNIEnv* ) välitetään argumenttina jokaiselle Java -menetelmään yhdistetylle natiivifunktiolle, mikä mahdollistaa vuorovaikutuksen JNI -ympäristön kanssa alkuperäisessä menetelmässä. Tämä JNI -rajapinnan osoitin voidaan tallentaa, mutta se pysyy voimassa vain nykyisessä säikeessä. Muiden säikeiden on ensin kutsuttava AttachCurrentThread (), jotta ne voidaan liittää VM: ään ja hankkia JNI -rajapintaosoitin. Kun natiivi on liitetty, se toimii kuin tavallinen Java -säie, joka toimii natiivimenetelmässä. Alkuperäinen säie pysyy kiinni virtuaalikoneessa, kunnes se kutsuu DetachCurrentThread () irrottaakseen itsensä.

JNI-kehys ei tarjoa automaattista roskien keräämistä muille kuin JVM-muistiresursseille, jotka on jaettu alkuperäisellä puolella suoritettavan koodin avulla. Näin ollen natiivi sivukoodi (kuten kokoonpanokieli) ottaa vastuun natiivikoodin hankkimien muistiresurssien nimenomaisesta vapauttamisesta.

Linux- ja Solaris -alustoilla, jos alkuperäinen koodi rekisteröi itsensä signaalinkäsittelijäksi, se voi siepata JVM: lle tarkoitettuja signaaleja. Vastuuketju voidaan sallia koodiksi paremmin välisen toimivat JVM. Windows-alustoilla Strukturoitujen poikkeusten käsittelyä (SEH) voidaan käyttää natiivikoodin käärimiseen SEH try/catch -lohkoihin koneen (CPU/FPU) tuottamien ohjelmistokeskeytysten kaappaamiseksi (kuten NULL-osoittimen käyttörikkomukset ja jako nollalla -toiminnot) ), ja käsitellä näitä tilanteita ennen kuin keskeytys levitetään takaisin JVM: ään (eli Java -sivukoodiin), mikä todennäköisesti johtaa käsittelemättömään poikkeukseen.

NewStringUTF-, GetStringUTFLength-, GetStringUTFChars-, ReleaseStringUTFChars- ja GetStringUTFRegion-toimintojen koodaus on "modifioitu UTF-8", joka ei kelpaa UTF-8 kaikille tuloille, mutta todella erilainen koodaus. Null merkki (U + 0000) ja codepoints ei mainita Basic Multilingual Plane (suurempi tai yhtä suuri kuin U + 10000, eli ne edustettuina korvike paria UTF-16) on koodattu eri tavoin modifioitu UTF-8. Monet ohjelmat käyttävät näitä toimintoja väärin ja käsittelevät palautetut tai toimintoihin siirretyt UTF-8-merkkijonot vakio-UTF-8-merkkijonoina muokattujen UTF-8-merkkijonojen sijaan. Ohjelmien tulisi käyttää NewString-, GetStringLength-, GetStringChars-, ReleaseStringChars-, GetStringRegion-, GetStringCritical- ja ReleaseStringCritical-toimintoja, jotka käyttävät UTF-16LE-koodausta pikku-endian-arkkitehtuureissa ja UTF-16BE-koodausta iso-endian-arkkitehtuureissa ja käyttävät sitten UTF-16-koodia 8 muuntorutiini.

Kartoitustyypit

Seuraavassa taulukossa esitetään tyypin kartoitus Java (JNI) ja natiivikoodi.

C Tyyppi Java -kielityyppi Kuvaus Kirjoita allekirjoitus
allekirjoittamaton char
uint8_t
jboolean allekirjoittamaton 8 bittiä Z
allekirjoitettu char
int8_t
jbyte allekirjoitettu 8 bittiä B
allekirjoittamaton lyhyt
uint16_t
jchar allekirjoittamaton 16 bittiä C
lyhyt
int16_t
j lyhyt allekirjoitettu 16 bittiä S
int
int32_t
jint allekirjoitettu 32 bittiä Minä

pitkä pitkä
int64_t

jlong allekirjoitettu 64 bittiä J
kellua jfloat 32 bittiä F
kaksinkertainen kaksinkertainen 64 bittiä D
mitätön V

Lisäksi allekirjoitus "L fully-qualified-class ;"tarkoittaisi tällä nimellä yksilöllisesti määriteltyä luokkaa; esim. allekirjoitus "Ljava/lang/String;"viittaa luokkaan java.lang.String. Lisäksi [allekirjoituksen etuliite tekee tämän tyyppisestä taulukosta; esimerkiksi, [Itarkoittaa int array tyyppi. Lopuksi voidallekirjoitus käyttää Vkoodia.

Nämä tyypit ovat vaihdettavissa. Voidaan käyttää jintsiellä, missä tavallisesti käytät int, ja päinvastoin, ilman tyyppikuvitusta . Java -merkkijonojen ja matriisien yhdistäminen alkuperäisiin merkkijonoihin ja matriiseihin on kuitenkin erilainen. Jos jstringkäytetään, jossa char *olisi, koodi saattaa kaatua JVM.

Esitys

JNI kärsii huomattavista yleiskustannuksista ja suorituskyvyn menetyksestä tietyissä olosuhteissa:

  • Funktion kutsut JNI -menetelmiin ovat kalliita, varsinkin kun menetelmää kutsutaan toistuvasti.
  • JVM ei sisällä natiivimenetelmiä, eikä menetelmää voi kääntää JIT: ksi , koska menetelmä on jo koottu.
  • Java -matriisi voidaan kopioida pääsyä varten natiivikoodiin ja myöhemmin kopioida takaisin. Hinta voi olla lineaarinen taulukon koossa.
  • Jos menetelmä välittää objektin tai sen on tehtävä soittopyyntö, alkuperäinen menetelmä todennäköisesti soittaa omia puheluitaan JVM: ään. Java -kenttien, -menetelmien ja -tyyppien käyttäminen alkuperäisestä koodista vaatii jotain vastaavaa kuin pohdintaa . Allekirjoitukset määritetään merkkijonoina ja niitä haetaan JVM: ltä. Tämä on sekä hidasta että virhealtista.
  • Java -merkkijonot ovat objekteja, niillä on pituus ja ne on koodattu. Merkkijonon käyttäminen tai luominen voi vaatia O (n) -kopion.

Vaihtoehdot

Microsoftin oma Java -virtuaalikoneen ( Visual J ++ ) toteutus sisälsi samanlaisen mekanismin natiivikoodin kutsumiseksi Javalta , nimeltään Raw Native Interface ( RNI ). Lisäksi sillä oli helppo tapa soittaa olemassa olevaan natiivikoodiin, joka ei ollut tietoinen Javasta, kuten (mutta ei rajoittuen) Windows -sovellusliittymään, nimeltään J/Direct . Kuitenkin Sunin ja Microsoftin välisen oikeudenkäynnin jälkeen tästä toteutuksesta Visual J ++: ta ei enää ylläpidetä.

RNI oli vähemmän hankala käyttää kuin JNI, koska kirjanpitoa Java -ympäristön osoittimella ei tarvittu. Sen sijaan kaikkiin Java -objekteihin voidaan päästä suoraan. Tämän helpottamiseksi käytettiin työkalua, joka loi otsikkotiedostot Java -luokista. Samoin J/Direct oli helpompi käyttää kuin tarvittavan natiivikirjaston ja JNI: n käyttäminen.

Java Native Access (JNA) on yhteisön kehittämä kirjasto, joka tarjoaa Java-ohjelmille helpon pääsyn jaettuihin alkuperäisiin kirjastoihin ilman JNI: tä.

Katso myös

Viitteet

Bibliografia

Ulkoiset linkit