Interfață nativă Java - Java Native Interface
În proiectarea software-ului , Java Native Interface ( JNI ) este un cadru de programare a interfeței cu funcții străine care permite codului Java care rulează într-o mașină virtuală Java (JVM) să apeleze și să fie apelat de aplicații native (programe specifice unei platforme hardware și a sistemului de operare ) și biblioteci scrise în alte limbi, cum ar fi C , C ++ și asamblare .
Obiective
JNI permite programatorilor să scrie metode native pentru a gestiona situațiile în care o aplicație nu poate fi scrisă în întregime în limbajul de programare Java, de exemplu, atunci când biblioteca de clase Java standard nu acceptă caracteristicile specifice platformei sau biblioteca de programe. De asemenea, este utilizat pentru a modifica o aplicație existentă (scrisă într-un alt limbaj de programare) pentru a fi accesibilă aplicațiilor Java. Multe dintre clasele de biblioteci standard depind de JNI pentru a oferi funcționalitate dezvoltatorului și utilizatorului, de exemplu I / O de fișiere și capabilități de sunet. Includerea implementărilor API sensibile la performanță și platformă în biblioteca standard permite tuturor aplicațiilor Java să acceseze această funcționalitate într-un mod sigur și independent de platformă.
Cadrul JNI permite unei metode native să utilizeze obiecte Java în același mod în care codul Java utilizează aceste obiecte. O metodă nativă poate crea obiecte Java și apoi inspecta și utiliza aceste obiecte pentru a-și îndeplini sarcinile. O metodă nativă poate inspecta și utiliza și obiecte create de codul aplicației Java.
Numai aplicațiile și applet-urile semnate pot invoca JNI.
O aplicație care se bazează pe JNI pierde portabilitatea platformei pe care o oferă Java (o soluție parțială este să scrieți o implementare separată a codului JNI pentru fiecare platformă și să solicitați Java să detecteze sistemul de operare și să îl încarce pe cel corect în timpul rulării).
Nu numai că poate interfața codul nativ cu Java, dar se poate baza și pe un Java Canvas, ceea ce este posibil cu Java AWT Native Interface . Procesul este aproape același, cu doar câteva modificări. Interfața nativă Java AWT este disponibilă numai de la J2SE 1.3.
JNI permite, de asemenea, accesul direct la codul de asamblare , fără a trece chiar printr-un pod C. Accesarea aplicațiilor Java de la asamblare este posibilă în același mod.
Proiecta
În cadrul JNI, funcțiile native sunt implementate în fișiere separate .c sau .cpp. (C ++ oferă o interfață ceva mai simplă cu JNI.) Când JVM invocă funcția, trece un JNIEnvpointer, un jobjectpointer și orice argumente Java declarate prin metoda Java. De exemplu, următoarele convertesc un șir Java într-un șir nativ:
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);
}
envPointerul este o structură care conține interfața cu JVM. Acesta include toate funcțiile necesare pentru a interacționa cu JVM și pentru a lucra cu obiecte Java. Exemplul funcțiilor JNI sunt convertirea matricelor native în / din matricele Java, convertirea șirurilor native în / din șirurile Java, instanțierea obiectelor, aruncarea excepțiilor etc. Practic, orice poate face codul Java se poate face folosind JNIEnv, deși cu o ușurință considerabil mai mică.
Argumentul objeste o referință la obiectul Java în interiorul căruia a fost declarată această metodă nativă.
Tipurile de date native pot fi mapate către / din tipurile de date Java. Pentru tipurile compuse, cum ar fi obiecte, tablouri și șiruri , codul nativ trebuie să convertească în mod explicit datele apelând metode în JNIEnv.
Un indicator de mediu JNI ( JNIEnv * ) este transmis ca argument pentru fiecare funcție nativă mapată la o metodă Java, permițând interacțiunea cu mediul JNI în cadrul metodei native. Acest indicator de interfață JNI poate fi stocat, dar rămâne valabil numai în firul curent. Alte fire trebuie să apeleze mai întâi AttachCurrentThread () pentru a se atașa la VM și pentru a obține un pointer de interfață JNI. Odată atașat, un fir nativ funcționează ca un fir Java obișnuit care rulează într-o metodă nativă. Firul nativ rămâne atașat la VM până când apelează DetachCurrentThread () pentru a se detașa.
Cadrul JNI nu oferă nicio colectare automată a gunoiului pentru resursele de memorie non-JVM alocate prin executarea codului pe partea nativă. În consecință, codul nativ (cum ar fi limbajul asamblării) își asumă responsabilitatea de a elibera în mod explicit orice astfel de resurse de memorie pe care le dobândește codul nativ.
Pe platformele Linux și Solaris, dacă codul nativ se înregistrează ca un handler de semnal, ar putea intercepta semnale destinate JVM. Un lanț de responsabilitate poate fi utilizat pentru a permite codului nativ să interacționeze mai bine cu JVM. Pe platformele Windows, Structured Exception Handling (SEH) poate fi utilizat pentru a înfășura codul nativ în blocurile try / catch SEH, astfel încât să capteze întreruperile software generate de mașină (CPU / FPU) (cum ar fi încălcările accesului la pointerul NULL și operațiile de divizare la zero) ), și pentru a gestiona aceste situații înainte ca întreruperea să fie propagată înapoi în JVM (adică codul lateral Java), după toate probabilitățile, rezultând o excepție nesoluționată.
Codificarea utilizată pentru funcțiile NewStringUTF, GetStringUTFLength, GetStringUTFChars, ReleaseStringUTFChars și GetStringUTFRegion este "UTF-8 modificat", care nu este UTF-8 valid pentru toate intrările, ci o codificare diferită. Caracterul nul (U + 0000) și punctele de cod care nu se află pe planul de bază multilingv (mai mare sau egal cu U + 10000, adică cele reprezentate ca perechi surogate în UTF-16) sunt codificate diferit în UTF-8 modificat. Multe programe folosesc de fapt aceste funcții incorect și tratează șirurile UTF-8 returnate sau trecute în funcții ca șiruri UTF-8 standard în loc de șiruri UTF-8 modificate. Programele ar trebui să utilizeze funcțiile NewString, GetStringLength, GetStringChars, ReleaseStringChars, GetStringRegion, GetStringCritical și ReleaseStringCritical, care utilizează codificarea UTF-16LE pe arhitecturi little-endian și UTF-16BE pe arhitecturi big-endian și apoi să utilizeze un UTF-UT pentru a utiliza un UTF 8 rutină de conversie.
Tipuri de cartografiere
Următorul tabel prezintă maparea tipurilor dintre Java (JNI) și codul nativ.
| Tipul C | Tipul limbajului Java | Descriere | Introduceți semnătura |
|---|---|---|---|
| unsigned char uint8_t |
jboolean | nesemnat 8 biți | Z |
| semnat char int8_t |
jbyte | semnat 8 biți | B |
| nesemnat scurt uint16_t |
jchar | nesemnat 16 biți | C |
| scurt int16_t |
scurt | semnat 16 biți | S |
| int int32_t |
jint | semnat 32 de biți | Eu |
|
lung lung |
jlong | semnat 64 de biți | J |
| pluti | jfloat | 32 de biți | F |
| dubla | jdouble | 64 de biți | D |
| nul | V |
În plus, semnătura "L fully-qualified-class ;"ar însemna clasa specificată în mod unic cu acel nume; de exemplu, semnătura "Ljava/lang/String;"se referă la clasă java.lang.String. De asemenea, prefixarea [la semnătură face matricea de acel tip; de exemplu, [Iînseamnă tipul matricei int. În cele din urmă, o voidsemnătură folosește Vcodul.
Aceste tipuri sunt interschimbabile. Se poate folosi jintacolo unde se folosește în mod normal int, și invers, fără a fi necesară nicio tipografie . Cu toate acestea, maparea dintre șirurile și matricile Java la șirurile și matricile native este diferită. Dacă a jstringeste utilizat acolo unde char *ar fi, codul ar putea bloca JVM.
Performanţă
JNI suferă pierderi considerabile de cheltuieli generale și de performanță în anumite circumstanțe:
- Apelurile funcționale către metodele JNI sunt costisitoare, mai ales atunci când se apelează în mod repetat o metodă.
- Metodele native nu sunt subliniate de JVM și nici metoda nu poate fi compilată JIT , deoarece metoda este deja compilată.
- O matrice Java poate fi copiată pentru acces în codul nativ și apoi copiată înapoi. Costul poate fi liniar în dimensiunea matricei.
- Dacă metoda este transmisă unui obiect sau trebuie să efectueze un apel invers, atunci metoda nativă va efectua propriile apeluri către JVM. Accesarea câmpurilor, metodelor și tipurilor Java din codul nativ necesită ceva similar cu reflectarea . Semnăturile sunt specificate în șiruri și interogate din JVM. Acest lucru este atât lent, cât și predispus la erori.
- Șirurile Java sunt obiecte, au lungime și sunt codificate. Accesarea sau crearea unui șir poate necesita o copie O (n).
Alternative
Implementarea proprietară Microsoft a unei mașini virtuale Java ( Visual J ++ ) a avut un mecanism similar pentru apelarea codului nativ din Java, numit Raw Native Interface ( RNI ). În plus, avea o modalitate ușoară de a apela codul nativ existent care nu cunoștea el însuși Java, cum ar fi (dar nu limitat la) API-ul Windows, numit J / Direct . Cu toate acestea, în urma litigiului Sun-Microsoft cu privire la această implementare, Visual J ++ nu mai este menținut.
RNI a fost mai puțin stângaci de utilizat decât JNI, deoarece nu a fost nevoie de contabilitate cu un indicator de mediu Java. În schimb, toate obiectele Java ar putea fi accesate direct. Pentru a facilita acest lucru, a fost utilizat un instrument care a generat fișiere antet din clasele Java. În mod similar, J / Direct a fost mai ușor de utilizat decât utilizarea bibliotecii native intermediare necesare și a JNI.
Java Native Access (JNA) este o bibliotecă dezvoltată de comunitate care oferă programelor Java acces facil la bibliotecile partajate native fără a utiliza JNI.
Vezi si
Referințe
Bibliografie
- Gordon, Rob (martie 1998). Essential Jni: Java Native Interface (prima ediție). Prentice Hall . p. 498. ISBN 0-13-679895-0.
- Liang, Sheng (20 iunie 1999). Java (TM) Native Interface: Ghidul și specificațiile programatorului (prima ediție). Prentice Hall . p. 320. ISBN 0-201-32577-2.
linkuri externe
- Specificația API Oracle JNI 6.0
- Interfață nativă Java: Ghid și specificații ale programatorului
- JNI în XCode de la Apple
- Manevrarea excepțiilor în JNI
- Java Link (wrapper modern C ++ 17 pentru JNI)