{"id":413,"date":"2011-11-03T14:59:17","date_gmt":"2011-11-03T12:59:17","guid":{"rendered":"http:\/\/www.kristiansborg.dk\/bibliotek\/?page_id=413"},"modified":"2011-11-03T15:00:05","modified_gmt":"2011-11-03T13:00:05","slug":"kapitel-9-java-native-interface-jni","status":"publish","type":"page","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/","title":{"rendered":"Kapitel 9 Java Native Interface (JNI)"},"content":{"rendered":"<p>Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface\u00a0(JNI).<\/p>\n<div style=\"border: 1px solid red; color: red\">\n<b>Du l\u00e6ser en gammel bog<\/b><br \/>\nDen bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\"  target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" \/>\n<\/div>\n<p>Med JNI er det muligt at tilg\u00e5 metoder, der er skrevet i et andet programmeringssprog og kompileret til operativsystemets bin\u00e6re kode. Det er ikke kun anvendeligt, n\u00e5r man skal tilg\u00e5 funktioner i operativsystemet, men ogs\u00e5 hvis man vil kombinere Java-programmer med programmer skrevet i andre programmeringssprog. Man kan for eksempel forestille sig, at realtidsdelen af en applikation skrives i C eller C++, mens den del, der foretager netv\u00e6rkskommunikation, skrives i Java.<\/p>\n<p>&nbsp;<\/p>\n<p>I dette kapitel vil det f\u00f8rst blive gennemg\u00e5et, hvordan man laver et simpelt program, der kalder en metode i et C++-program. Herefter vil de mere avancerede muligheder blive gennemg\u00e5et.<\/p>\n<p>&nbsp;<\/p>\n<p>Kapitlet kr\u00e6ver et vist kendskab til C++, da alle eksempler p\u00e5 native kode vil blive skrevet i det sprog. Som compiler er Microsoft Visual C++ 4.2 benyttet.<\/p>\n<p>&nbsp;<\/p>\n<h1>Et simpelt kald til en native metode<\/h1>\n<p>Processen med at implementere native kode i sit Java-program kan opdeles i fem trin:<\/p>\n<ol>\n<li>Skriv Java-koden.<\/li>\n<li>Kompil\u00e9r Java-koden.<\/li>\n<li>Opret en headerfil.<\/li>\n<li>Skriv implementeringen af den native metode.<\/li>\n<li>Kompil\u00e9r den native kode.<\/li>\n<\/ol>\n<p>Java-koden skal best\u00e5 af to ting. Dels skal den eller de native metoder defineres, og der skal v\u00e6re en statisk programblok i klassen, der indl\u00e6ser det <em>library<\/em>, der indeholder den native metode. Et library\u00a0er det, der i Windows kendes som en DLL-fil (Dynamic Link Library).<\/p>\n<p>Ved den native metode angives kun metodens hoved. Dette markeres med det reserverede ord native. Indl\u00e6sningen af library\u2019et sker ved hj\u00e6lp af<\/p>\n<p>&nbsp;<\/p>\n<p>metoden System.loadLibrary. Det betyder, at en klasse med native metoder kan komme til at se s\u00e5ledes ud:<\/p>\n<p>public class SigHej<\/p>\n<p>{<\/p>\n<p>public native void hejsa();<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;hej&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Fordelen ved at placere loadLibrary-metodekaldet i en statisk blok er, at man er sikker p\u00e5, at det bliver udf\u00f8rt, hvadenten klassen initialiseres eller ej. Hvor constructors kun bliver udf\u00f8rt, n\u00e5r en klasse instantieres, bliver den statiske blok udf\u00f8rt, s\u00e5 snart klassen bliver indl\u00e6st.<\/p>\n<p>&nbsp;<\/p>\n<p>Det er imidlertid ikke nok bare at definere den native metode. Den skal ogs\u00e5 kaldes. Dette sker \u2013 i dette eksempel \u2013 fra en klasse, der hedder NativeHej:<\/p>\n<p>&nbsp;<\/p>\n<p>public class NativeHej<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>new SigHej().hejsa();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses, kaldes den native metode ligesom alle andre metoder. Det er s\u00e5ledes ikke muligt for brugeren at se, om en metode er skrevet i Java eller et andet sprog.<\/p>\n<p>&nbsp;<\/p>\n<p>Ligeledes kompileres programmet p\u00e5 pr\u00e6cis samme m\u00e5de som andre Java-programmer.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r Java-koden er kompileret, kan man begynde at koncentrere sig om C++-koden. F\u00f8rste skridt i den forbindelse er at oprette en headerfil. Det g\u00f8r man ved hj\u00e6lp af programmet javah, der er inkluderet i Suns JDK. Dette program arbejder p\u00e5 den klassefil, der indeholder definitionen af den native metode \u2013 i dette eksempel SigHej \u2013 og opretter p\u00e5 den baggrund en headerfil, der kan inkluderes i C++-programmet. javah kaldes i Windows 95 med f\u00f8lgende kommando:<\/p>\n<p>&nbsp;<\/p>\n<p>javah \u2013jni SigHej<\/p>\n<p>&nbsp;<\/p>\n<p>javah genererer en headerfil ved navn SigHej.h. Den fil ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class SigHej *\/<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_SigHej<\/p>\n<p>#define _Included_SigHej<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>&nbsp;<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 SigHej<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 hejsa<\/p>\n<p>* Signature: ()V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_SigHej_hejsa<\/p>\n<p>(JNIEnv *, jobject);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>Java_SigHej_hejsa er den funktion, der skal implementeres i C++. Man bruger signaturen fra header-filen, n\u00e5r man implementerer funktionen. Funktionen navngives efter f\u00f8lgende regler: F\u00f8rst s\u00e6ttes navnet Java. Derefter kommer navnet p\u00e5 den pakke, klassen befinder sig i. Det n\u00e6ste komponent er navnet p\u00e5 klassen, og det sidste er navnet p\u00e5 selve metoden. Elementerne adskilles med en understregning (_). Hvis klassen ikke befinder sig i en pakke \u2013 som i dette tilf\u00e6lde \u2013 undlades dette element i funktionsnavnet.<\/p>\n<p>&nbsp;<\/p>\n<p>I headerfilen har funktionen 2 parametre, selvom den oprindelige Java-metode ingen parametre havde. JNI kr\u00e6ver, at alle native metoder har disse to parametre. Det f\u00f8rste parameter er en pointer til et JNIEnv-objekt. Dette objekt bruges til at tilg\u00e5 variabler og parametre, der gives den native metode fra Java-systemet. Det andet parameter, er et jobject. Dette er selve det objekt, metoden befinder sig i. Hvis metoden i Java er statisk, vil det v\u00e6re en reference til selve klassen. jobject-referencen minder en smule om this-pointeren i C++. Blot skal man v\u00e6re opm\u00e6rksom p\u00e5, at man i en statisk metode for en reference til klassen i stedet for til et objekt.<\/p>\n<p>&nbsp;<\/p>\n<p>Da dette er et simpelt eksempel, vil ingen af de to parametre blive brugt, men de vil blive gennemg\u00e5et senere i kapitlet.<\/p>\n<p>&nbsp;<\/p>\n<p>Med udgangspunkt i den genererede headerfil, kan man nu skrive implementeringen i et andet programmeringssprog end Java \u2013 i dette eksempel C++. Her kommer C++-koden til at se s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>#include &lt;stdio.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;sighej.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_SigHej_hejsa (JNIEnv *, jobject)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Hejsa verden!\\n&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Implementeringen af selve funktionen er simpel. printf-funktionen bruges til at udskrive beskeden \u2013 derfor bliver stdio.h inkluderet. Naturligvis bliver ogs\u00e5 sighej.h inkluderet. Hver gang man implementerer en native metode, skal man inkludere filen jni.h. Denne findes i biblioteket include\\ under roden af Java-installationen. Denne fil inkluderer jni_md.h, der findes i biblioteket include\\win32.<\/p>\n<p>&nbsp;<\/p>\n<p>Med Microsoft Visual C++ 4.2 skal f\u00f8lgende kommando bruges til at kompilere C++-programmet<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>cl -Ic:\\jdk12\\include -Ic:\\jdk12\\include\\win32 -If:\\msdev\\include -LD -ML hejImpl.cpp -Fehej.dll<\/p>\n<p>&nbsp;<\/p>\n<p>Man skal naturligvis \u00e6ndre placeringen af include-filerne, hvis JDK ikke er installeret i c:\\jdk12.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r C++-filen er kompileret, er Java-applikationen klar til at blive k\u00f8rt. Det g\u00f8r man \u2013 som vanligt \u2013 ved at skrive<\/p>\n<p>&nbsp;<\/p>\n<p>java NativeHej<\/p>\n<p>&nbsp;<\/p>\n<p>Nu hvor det grundl\u00e6ggende i JNI er blevet gennemg\u00e5et, kan man g\u00e5 videre med de mere avancerede muligheder.<\/p>\n<p>&nbsp;<\/p>\n<h1>Parametre<\/h1>\n<p>&nbsp;<\/p>\n<p>I ovenst\u00e5ende eksempel havde den native metode ingen parametre og heller ingen returv\u00e6rdi. I dette afsnit vil det blive gennemg\u00e5et, hvordan man h\u00e5ndterer parametre, og hvordan man returnerer v\u00e6rdier.<\/p>\n<p>&nbsp;<\/p>\n<p>Som eksempel vil blive brugt en klasse \u2013 FileInfo \u2013 der har en metode, som hedder fileSize. fileSize returnerer st\u00f8rrelsen af en given fil i kilobytes. Navnet p\u00e5 filen gives med som parameter. Det betyder, at klassen kommer til at se s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>public class FileInfo<\/p>\n<p>{<\/p>\n<p>public native int fileSize (String filename);<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;File&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Baseret p\u00e5 den kompilerede klassefil genererer javah f\u00f8lgende headerfil:<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class FileInfo *\/<\/p>\n<p>#ifndef _Included_FileInfo<\/p>\n<p>#define _Included_FileInfo<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 FileInfo<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 fileSize<\/p>\n<p>* Signature: (Ljava\/lang\/String;)I<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT jint JNICALL Java_FileInfo_fileSize<\/p>\n<p>(JNIEnv *, jobject, jstring);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>Her ses det, at signaturen af metoden er \u00e6ndret. Udover de to parametre, der blev diskuteret i forrige afsnit, er String i parameterlisten blevet erstattet af jstring, mens returtypen int er blevet til jint. Dette skyldes, at javah foretager en automatisk konvertering fra Java-typer til JNI-typer.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende skema viser sammenh\u00e6ngen mellem Javas primitive type og JNI typerne.<\/p>\n<p>&nbsp;<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td width=\"217\" valign=\"top\">java-type<\/td>\n<td width=\"217\" valign=\"top\">jni-type<\/td>\n<td width=\"217\" valign=\"top\">st\u00f8rrelse i bits<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Boolean<\/td>\n<td width=\"217\" valign=\"top\">jboolean<\/td>\n<td width=\"217\" valign=\"top\">8, unsigned<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">byte<\/td>\n<td width=\"217\" valign=\"top\">jbyte<\/td>\n<td width=\"217\" valign=\"top\">8<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Char<\/td>\n<td width=\"217\" valign=\"top\">jchar<\/td>\n<td width=\"217\" valign=\"top\">16, unsigned<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Short<\/td>\n<td width=\"217\" valign=\"top\">jshort<\/td>\n<td width=\"217\" valign=\"top\">16<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Int<\/td>\n<td width=\"217\" valign=\"top\">jint<\/td>\n<td width=\"217\" valign=\"top\">32<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Long<\/td>\n<td width=\"217\" valign=\"top\">jlong<\/td>\n<td width=\"217\" valign=\"top\">64<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Float<\/td>\n<td width=\"217\" valign=\"top\">jfloat<\/td>\n<td width=\"217\" valign=\"top\">32<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Double<\/td>\n<td width=\"217\" valign=\"top\">jdouble<\/td>\n<td width=\"217\" valign=\"top\">64<\/td>\n<\/tr>\n<tr>\n<td width=\"217\" valign=\"top\">Void<\/td>\n<td width=\"217\" valign=\"top\">Void<\/td>\n<td width=\"217\" valign=\"top\">ingen<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Objekter overf\u00f8res som referencer. Alle objekter overf\u00f8res som jobject. De mest anvendte Java-objekter er imidlertid defineret som subklasser af jobject. Dette skema viser, hvordan bestemte Java-klasser er defineret i JNI:<\/p>\n<p>&nbsp;<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td width=\"326\" valign=\"top\">Java-klasse<\/td>\n<td width=\"326\" valign=\"top\">JNI-klasse<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Java.lang.object<\/td>\n<td width=\"326\" valign=\"top\">Jobject<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">java.lang.Class<\/td>\n<td width=\"326\" valign=\"top\">Jclass<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">java.lang.String<\/td>\n<td width=\"326\" valign=\"top\">Jstring<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">java.lang.Object[]<\/td>\n<td width=\"326\" valign=\"top\">Jobjectarray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">boolean[]<\/td>\n<td width=\"326\" valign=\"top\">Jbooleanarray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">byte[]<\/td>\n<td width=\"326\" valign=\"top\">Jbytearray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">char[]<\/td>\n<td width=\"326\" valign=\"top\">Jchararray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">double[]<\/td>\n<td width=\"326\" valign=\"top\">Jdoublearray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">float[]<\/td>\n<td width=\"326\" valign=\"top\">Jfloatarray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">int[]<\/td>\n<td width=\"326\" valign=\"top\">Jintarray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">long[]<\/td>\n<td width=\"326\" valign=\"top\">jlongarray<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">short[]<\/td>\n<td width=\"326\" valign=\"top\">jshortarray<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h2>Strenge<\/h2>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man bruger variabler fra Java i eksempelvis C++, skal man v\u00e6re opm\u00e6rksom p\u00e5, at de ikke n\u00f8dvendigvis er defineret p\u00e5 samme m\u00e5de som tilsvarende variabler i sproget. Hvis man eksempelvis fors\u00f8ger at udskrive en jstring, resulterer det sandsynligvis i, at programmet g\u00e5r ned.<\/p>\n<p>&nbsp;<\/p>\n<p>I stedet skal man bruge de funktioner, JNI stiller til r\u00e5dighed til at konvertere jstring til en C++-streng (char *).<\/p>\n<p>&nbsp;<\/p>\n<p>For at konvertere parametret i dette eksempel til et char-array skal den f\u00f8lgende kode bruges:<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT jint JNICALL Java_FileInfo_fileSize (JNIEnv *env, jobject me, jstring filename)<\/p>\n<p>{<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>.<\/p>\n<p>.<\/p>\n<p>.<\/p>\n<p>env-&gt;ReleaseStringUTFChars(filename, fname);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Funktionen GetStringUTFChars\u00a0konverterer en jstring til et char-array. N\u00e5r man er f\u00e6rdig med at bruge strengen, skal man huske at frigive den. Det g\u00f8r man ved hj\u00e6lp af funktionen ReleaseStringUTFChars. Kalder man ikke denne funktion, frigives hukommelsen ikke, og det vil med tiden medf\u00f8re, at der ikke er mere ledig hukommelse. Dette skyldes, at garbage collector\u2019en ikke virker i native metoder. Her er man overladt til at bruge de metoder, der findes i det sprog, man benytter.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man f\u00e5r brug for at konvertere et char-array til en jstring, giver JNI ogs\u00e5 mulighed for det. Det sker gennem af NewStringUTF-funktionen. Den bruges s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>char tekst[] = &#8220;Her er lidt tekst&#8221;;<\/p>\n<p>env-&gt;NewStringUTF(tekst);<\/p>\n<p>&nbsp;<\/p>\n<p>JNI stiller ogs\u00e5 andre funktioner til strengh\u00e5ndtering til r\u00e5dighed:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>GetStringChars\u00a0tager en Java-streng som parameter og returnerer en pointer til et array af de Unicode-tegn, der udg\u00f8r strengen.<\/li>\n<li>ReleaseStringChars\u00a0frigiver den hukommelse, GetStringChars l\u00e5ste.<\/li>\n<li>NewString\u00a0opretter et jstring-objekt baseret p\u00e5 et array af Unicode-tegn.<\/li>\n<li>GetStringLength\u00a0returnerer l\u00e6ngden af en streng, der best\u00e5r af et array af Unicode-tegn.<\/li>\n<li>GetStringUTFLength\u00a0returnerer l\u00e6ngden af en UTF-streng.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Det er ikke n\u00f8dvendigt at benytte disse funktioner i fileInfo-eksemplet. Her beh\u00f8ver man blot at finde filst\u00f8rrelsen og returnere denne:<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>#include &lt;io.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;FileInfo.h&#8221;<\/p>\n<p>JNIEXPORT jint JNICALL Java_FileInfo_fileSize (JNIEnv *env, jobject me, jstring filename)<\/p>\n<p>{<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>int f = _open (fname, 0);<\/p>\n<p>int filesize = _filelength (f) &gt;&gt; 10;<\/p>\n<p>_close (f);<\/p>\n<p>env-&gt;ReleaseStringUTFChars(filename, fname);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>return filesize;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses, kan filesize returneres uden videre. Mellem Javas primitive typer og de tilsvarende typer i JNI er ingen konvertering n\u00f8dvendig. FileInfo-klassen er nu klar til brug. F\u00f8lgende klasse viser, hvordan den kan bruges:<\/p>\n<p>&nbsp;<\/p>\n<p>public class FileApp<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;St\u00f8rrelsen af &#8221; + args[0] + &#8221; er &#8221; + new FileInfo().fileSize(args[0]) + &#8221; Kb.&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h2>Arrays<\/h2>\n<p>&nbsp;<\/p>\n<p>Ligesom strenge skal behandles p\u00e5 en speciel m\u00e5de, g\u00e6lder der ogs\u00e5 s\u00e6rlige regler for arrays. Som n\u00e6vnt tidligere bliver arrays overf\u00f8rt til en JNI-type, der svarer til den type elementer, der findes i arrayet.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man vil have en native metode til at udskrive samtlige elementer i et int-array, kan Java-filen se s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>public class ArrayPrint<\/p>\n<p>{<\/p>\n<p>public native void print (int array[]);<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;array&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>javah vil s\u00e5 generere en headerfil, der ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class ArrayPrint *\/<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_ArrayPrint<\/p>\n<p>#define _Included_ArrayPrint<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 ArrayPrint<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 print<\/p>\n<p>* Signature: ([I)V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_ArrayPrint_print<\/p>\n<p>(JNIEnv *, jobject, jintArray);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>Det ses, at parametret int array[] som forventet er blevet til jintArray.<\/p>\n<p>&nbsp;<\/p>\n<p>Det f\u00f8rste, man g\u00f8r, n\u00e5r man vil benytte et array i JNI, er at finde ud af arrayets l\u00e6ngde. Dette kan man g\u00f8re, fordi arrays i Java \u2013 i mods\u00e6tning til arrays i C++ \u00ad\u2013 indeholder information om deres l\u00e6ngde. Man finder et arrays l\u00e6ngde ved at benytte funktionen GetArrayLength, der stilles til r\u00e5dighed af JNIEnv-objektet.<\/p>\n<p>&nbsp;<\/p>\n<p>I C++ er et array blot en pointer til det f\u00f8rste element i arrayet. Det vil sige, at man for at konvertere et Java-array til et C++-array kun beh\u00f8ver at skaffe en pointer til element 0. Det kan man g\u00f8re ved hj\u00e6lp af funktionen GetIntArrayElements. Denne funktion tager array\u2019et og indekset som parametre. I dette tilf\u00e6lde vil indekset v\u00e6re 0. Herefter kan array\u2019et behandles som alle andre C++-arrays. N\u00e5r man er f\u00e6rdig med at benytte array\u2019et skal man frigive den hukommelse, det har optaget. Det g\u00f8r man ved at kalde ReleaseIntArrayElements. Grunden til dette er, at Javas garbage collector normalt har mulighed for at flytte objekter i hukommelsen. I forbindelse med JNI bliver det imidlertid garanteret, at objekterne ikke flyttes. Dette g\u00f8res enten ved at oprette en kopi af dem, i et hukommelsesomr\u00e5de, der ikke tillader flytning, eller ved at m\u00e6rke objekterne.<\/p>\n<p>&nbsp;<\/p>\n<p>F\u00f8lgende eksempel viser, hvordan et Java-array kan h\u00e5ndteres i C++:<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>#include &lt;stdio.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;ArrayPrint.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_ArrayPrint_print (JNIEnv *env, jobject me, jintArray array)<\/p>\n<p>{<\/p>\n<p>int len = env-&gt;GetArrayLength (array);<\/p>\n<p>jint *cpp_array = env-&gt;GetIntArrayElements(array,0);<\/p>\n<p>&nbsp;<\/p>\n<p>for (int i = 0; i &lt; len; i++)<\/p>\n<p>printf (&#8220;%i\\n&#8221;, cpp_array[i]);<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ReleaseIntArrayElements(array, cpp_array, 0);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses, h\u00e5ndteres array\u2019et som et array af jint i stedet for et array af int. Det skyldes, af de variabler, der er int i Java er long i C++. For at undg\u00e5 denne forvirring, kan man bruge JNI\u2019s typer i stedet.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende klasse viser, hvordan ArrayPrint kan anvendes:<\/p>\n<p>&nbsp;<\/p>\n<p>public class ArrayApp<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>int i[] = {1,2,3,4,5,6,7,8,9};<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>new ArrayPrint().print (i);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>I dette eksempel er array\u2019et ikke s\u00e6rlig stort, men hvis man arbejder med store arrays, kan det v\u00e6re et problem, at GetIntArrayElements\u00a0returnerer hele array\u2019et. Det vil sige, at det er alle elementerne i array\u2019et, der skal kopieres i hukommelsen. Hvis man kun skal bruge en lille del af array\u2019et og gerne vil undg\u00e5 un\u00f8dig kopiering, b\u00f8r man anvende GetIntArrayRegion\u00a0i stedet.<\/p>\n<p>&nbsp;<\/p>\n<p>S\u00e5l\u00e6nge man arbejder p\u00e5 arrays af primitive typer, foreg\u00e5r det relativt smertefrit. Hvis man arbejder p\u00e5 et array af typen Object i stedet, kan man imidlertid ikke bruge en get-funktion til at hente hele array\u2019et. Her m\u00e5 man bruge GetObjectArrayElement, der kun kan returnere et element ad gangen.<\/p>\n<p>&nbsp;<\/p>\n<h1>Kald af Java-metoder<\/h1>\n<p>&nbsp;<\/p>\n<p>Som det er vist tidligere, kan native metoder fra Java kaldes p\u00e5 samme m\u00e5de som andre Java-metoder. Det er imidlertid ikke helt s\u00e5 simpelt at kalde Java-funktioner fra andre programmeringssprog.<\/p>\n<p>&nbsp;<\/p>\n<p>For at vise, hvordan en Java-metode kan blive kaldt fra C++, gennemg\u00e5s her et eksempel, hvor en Java-metode kalder en C++-metode, der kalder en Java-funktion.<\/p>\n<p>&nbsp;<\/p>\n<p>Java-klassen ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>public class MethodCall<\/p>\n<p>{<\/p>\n<p>public native void call();<\/p>\n<p>&nbsp;<\/p>\n<p>public void callback()<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;callback() udf\u00f8rt&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;Method&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Ved at bruge javah p\u00e5 den kompilerede kode af ovenst\u00e5ende klasse f\u00e5r man denne headerfil:<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class MethodCall *\/<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_MethodCall<\/p>\n<p>#define _Included_MethodCall<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>&nbsp;<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0 \u00a0MethodCall<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 call<\/p>\n<p>* Signature: ()V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_MethodCall_call<\/p>\n<p>(JNIEnv *, jobject);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>F\u00f8r man kan kalde en Java-metode, er man n\u00f8dt til at vide, hvilken klasse den er en del af. I dette tilf\u00e6lde er det den samme klasse, som metoden selv er del af. Derfor kan man bruge jobject-objektet som gives med som parameter til at bestemme klassen. Funktionen GetObjectClass\u00a0returnerer den klasse, et givent objekt er af.<\/p>\n<p>&nbsp;<\/p>\n<p>Herefter skal man have en reference til den metode, der skal kaldes. Dette opn\u00e5r man gennem funktionen GetMethodID. Denne metode skal som parametre have den klasse, metoden skal findes i, navnet p\u00e5 metoden og dens signatur. Navnet p\u00e5 metoden er som regel ligetil, men man skal v\u00e6re opm\u00e6rksom p\u00e5, at constructors \u2013 der jo normalt ikke har noget navn \u2013 gives navnet &lt;init&gt;.<\/p>\n<p>&nbsp;<\/p>\n<p>Signaturerne formuleres p\u00e5 en lidt speciel m\u00e5de. Den generelle form er<\/p>\n<p>&nbsp;<\/p>\n<p>(parametre)returntype<\/p>\n<p>&nbsp;<\/p>\n<p>Hver af Javas primitive typer har en et-bogstavsforkortelse, der bruges i b\u00e5de parameterlisten og returtypen. Forkortelserne er defineret som f\u00f8lger:<\/p>\n<p>&nbsp;<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td width=\"326\" valign=\"top\">Z<\/td>\n<td width=\"326\" valign=\"top\">boolean<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">B<\/td>\n<td width=\"326\" valign=\"top\">byte<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">C<\/td>\n<td width=\"326\" valign=\"top\">char<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">S<\/td>\n<td width=\"326\" valign=\"top\">short<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">I<\/td>\n<td width=\"326\" valign=\"top\">int<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">L<\/td>\n<td width=\"326\" valign=\"top\">long<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">F<\/td>\n<td width=\"326\" valign=\"top\">float<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">D<\/td>\n<td width=\"326\" valign=\"top\">double<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">V<\/td>\n<td width=\"326\" valign=\"top\">void<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Vil man anvende objekter i stedet for primitive typer, skriver man<\/p>\n<p>&nbsp;<\/p>\n<p>L<em>klassenavn<\/em><\/p>\n<p><em> <\/em><\/p>\n<p>For eksempel angiver<\/p>\n<p>&nbsp;<\/p>\n<p>Ljava.lang.String<\/p>\n<p>&nbsp;<\/p>\n<p>et objekt af typen String.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Arrays angives med en \u00e5ben kantet parentes ([) efterfulgt af den type, array\u2019ets elementer er af. Eksempelvis vil<\/p>\n<p>&nbsp;<\/p>\n<p>[Ljava.lang.String<\/p>\n<p>&nbsp;<\/p>\n<p>angive et array af tekststrenge.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man har brug for at generere mange signaturer, kan man v\u00e6lge at bruge programmet javap. Ved at angive \u2013s som parameter vises de interne signaturer, der blandt andet anvendes i JNI. Skriver man for eksempel<\/p>\n<p>&nbsp;<\/p>\n<p>Javap \u2013s java.lang.reflect.Array<\/p>\n<p>&nbsp;<\/p>\n<p>f\u00e5r man f\u00f8lgende oversigt over Array-klassen. javap viser b\u00e5de den kendte Java-signatur og den interne signatur, s\u00e5 man har mulighed for at sammenligne og p\u00e5 den m\u00e5de f\u00e5 mere erfaring med det interne format.<\/p>\n<p>&nbsp;<\/p>\n<p>Compiled from Array.java<\/p>\n<p>public final class Array extends java.lang.Object<\/p>\n<p>\/* ACC_SUPER bit set *\/<\/p>\n<p>{<\/p>\n<p>public static native java.lang.Object get(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)Ljava\/lang\/Object;\u00a0\u00a0 *\/<\/p>\n<p>public static native boolean getBoolean(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)Z\u00a0\u00a0 *\/<\/p>\n<p>public static native byte getByte(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)B\u00a0\u00a0 *\/<\/p>\n<p>public static native char getChar(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)C\u00a0\u00a0 *\/<\/p>\n<p>public static native double getDouble(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)D\u00a0\u00a0 *\/<\/p>\n<p>public static native float getFloat(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)F\u00a0\u00a0 *\/<\/p>\n<p>public static native int getInt(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)I\u00a0\u00a0 *\/<\/p>\n<p>public static native int getLength(java.lang.Object);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;)I\u00a0\u00a0 *\/<\/p>\n<p>public static native long getLong(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)J\u00a0\u00a0 *\/<\/p>\n<p>public static native short getShort(java.lang.Object, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;I)S\u00a0\u00a0 *\/<\/p>\n<p>public static java.lang.Object newInstance(java.lang.Class, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Class;I)Ljava\/lang\/Object;\u00a0\u00a0 *\/<\/p>\n<p>public static java.lang.Object newInstance(java.lang.Class, int[]);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Class;[I)Ljava\/lang\/Object;\u00a0\u00a0 *\/<\/p>\n<p>public static native void set(java.lang.Object, int, java.lang.Object);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;ILjava\/lang\/Object;)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setBoolean(java.lang.Object, int, boolean);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IZ)V\u00a0\u00a0 *\/<\/p>\n<p>&nbsp;<\/p>\n<p>public static native void setByte(java.lang.Object, int, byte);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IB)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setChar(java.lang.Object, int, char);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IC)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setDouble(java.lang.Object, int, double);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;ID)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setFloat(java.lang.Object, int, float);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IF)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setInt(java.lang.Object, int, int);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;II)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setLong(java.lang.Object, int, long);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IJ)V\u00a0\u00a0 *\/<\/p>\n<p>public static native void setShort(java.lang.Object, int, short);<\/p>\n<p>\/*\u00a0\u00a0 (Ljava\/lang\/Object;IS)V\u00a0\u00a0 *\/<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Det at hente et metode-ID er en tidsm\u00e6ssig dyr operation, og derfor er den adskilt fra selve metodekaldet, s\u00e5 man kan hente ID\u2019et \u00e9n gang, og herefter kalde metoden flere gange. Man skal blot t\u00e6nke p\u00e5, at ID\u2019et kun er gyldigt, s\u00e5 l\u00e6nge den klasse, der indeholder metoden, ikke bliver fjernet fra hukommelsen.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man har metode-ID, kan man kalde metoden ved hj\u00e6lp af CallVoidMethod-funktionen. Parametre til denne funktion er det objekt, metoden skal kaldes p\u00e5 samt metode-ID. Hvis der ogs\u00e5 er parametre til den metode, der skal kaldes, kan disse gives med som ekstra parametre til CallVoidMethod.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende kode viser, hvordan et kald af en Java-metode foretages fra et C++ program.<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>#include &lt;stdio.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;MethodCall.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_MethodCall_call (JNIEnv *env, jobject me)<\/p>\n<p>{<\/p>\n<p>jclass classname = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID id = env-&gt;GetMethodID (classname, &#8220;callback&#8221;, &#8220;()V&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>if (id == 0)<\/p>\n<p>return;<\/p>\n<p>&nbsp;<\/p>\n<p>printf (&#8220;Native metode kaldt.\\n&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;CallVoidMethod(me, id);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Ovenst\u00e5ende eksempel viste, hvordan man kaldte en instansmetode \u2013 en ikke-statisk metode. Hvis man vil kalde en statisk metode, er fremgangsm\u00e5den lidt anderledes. I stedet for GetMethodID skal man bruge GetStaticMethodID, og i stedet for CallVoidMethod skal man bruge CallStaticVoidMethod.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man vil kalde en funktion, der returnerer andet end void, skal man bruge en af de andre Call&lt;type&gt;Method-funktioner \u2013 for eksempel CallBooleanMethod\u00a0osv.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis en klasse har overskrevet en af superklassens metoder, betyder det ikke, at man ikke har mulighed for at kalde superklassens metoder. Det g\u00f8r man ved at f\u00e5 et metode-ID fra superklassen ved hj\u00e6lp af GetMethodID-funktionen. Dern\u00e6st kalder man metoden gennem CallNonvirtualVoidMethod \u00a0eller lignende, alt efter hvilken returtype metoden har. Parametrene til funktionen er objektet, superklassen, ID\u2019et og eventuelle parametre, der skal sendes med til den metode man kalder.<\/p>\n<p>&nbsp;<\/p>\n<h1>Exceptions<\/h1>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man kalder Java-metoder, risikerer man, at der opst\u00e5r en exception. Selvom C++ har et system, der kan h\u00e5ndtere exceptions, er der ingen garanti for, at alle programmeringssprog, der kan benytte JNI, har det. Derfor er der til JNI udviklet et specielt system til h\u00e5ndtering af exceptions i andre programmeringssprog end Java. For at vise, hvordan man kan h\u00e5ndtere exceptions, vil der blive oprettet en klasse med en funktion, hvis eneste form\u00e5l er at lave en exception. Klassen vil ogs\u00e5 have en native funktion, der kalder exception-funktionen.<\/p>\n<p>&nbsp;<\/p>\n<p>public class ThrowException<\/p>\n<p>{<\/p>\n<p>public void doThrow() throws NullPointerException<\/p>\n<p>{<\/p>\n<p>throw new NullPointerException (&#8220;Denne funktion er tom&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public native void testException();<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary(&#8220;Exception&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Det giver en headerfil, der ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class ThrowException *\/<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_ThrowException<\/p>\n<p>#define _Included_ThrowException<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 ThrowException<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 testException<\/p>\n<p>* Signature: ()V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_ThrowException_testException<\/p>\n<p>(JNIEnv *, jobject);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>Den native metode skal f\u00f8rst kalde metoden doThrow. Det g\u00f8res p\u00e5 den m\u00e5de, der blev beskrevet tidligere i kapitlet. Herefter kontrolleres det, om der er opst\u00e5et en exception. Denne kontrol foreg\u00e5r ved, at der oprettes en jthrowable-variabel. Denne s\u00e6ttes lig med returv\u00e6rdien af ExceptionOccurred. Hvis denne variabel har en v\u00e6rdi forskellig fra nul, er der opst\u00e5et en exception. Man kan herefter f\u00e5 informationer om exception\u2019en udskrevet ved at kalde ExceptionDescribe. N\u00e5r man har h\u00e5ndteret den p\u00e5g\u00e6ldende exception, skal man kalde ExceptionClear for at fjerne exception\u2019en fra listen over opst\u00e5ede exceptions. Nedenst\u00e5ende C++ program viser, hvordan det kan g\u00f8res.<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;ThrowException.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_ThrowException_testException (JNIEnv *env, jobject me)<\/p>\n<p>{<\/p>\n<p>jclass thisclass = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID methodID = env-&gt;GetMethodID (thisclass, &#8220;doThrow&#8221;, &#8220;()V&#8221;);<\/p>\n<p>env-&gt;CallVoidMethod (me, methodID);<\/p>\n<p>&nbsp;<\/p>\n<p>jthrowable exception;<\/p>\n<p>exception = env-&gt;ExceptionOccurred();<\/p>\n<p>if (exception)<\/p>\n<p>{<\/p>\n<p>env-&gt;ExceptionDescribe();<\/p>\n<p>env-&gt;ExceptionClear();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Det er uhyre vigtigt, at man h\u00e5ndterer eventuelle exceptions, f\u00f8r man kalder andre JNI-metoder. Ellers risikerer man, at disse opdager den p\u00e5g\u00e6ldende exception<\/p>\n<p>&nbsp;<\/p>\n<p>og tror, at det er deres skyld, at den er opst\u00e5et. Det er s\u00e5ledes udefineret, hvad der sker, hvis man kalder en JNI-metode med en exception liggende i listen, men det er n\u00e6ppe det, man \u00f8nskede, der skulle ske.<\/p>\n<p>&nbsp;<\/p>\n<p>Der er kun tre metoder, der risikofrit kan kaldes, s\u00e5l\u00e6nge der eksisterer en uh\u00e5ndteret exception. Disse er<\/p>\n<ul>\n<li>ExceptionOccured<\/li>\n<li>ExceptionDescribe<\/li>\n<li>ExceptionClear.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende klasse kan bruges til at teste implementeringen af exception-eksemplet.<\/p>\n<p>&nbsp;<\/p>\n<p>public class ExceptionApp<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>new ThrowException().testException();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>K\u00f8rsel af ovenst\u00e5ende program giver f\u00f8lgende udskrift:<\/p>\n<p>&nbsp;<\/p>\n<p>java.lang.NullPointerException: Denne funktion er tom<\/p>\n<p>at ThrowException.doThrow(ThrowException.java:5)<\/p>\n<p>at ThrowException.testException(Native Method)<\/p>\n<p>at ExceptionApp.main(ExceptionApp.java:5)<\/p>\n<p>Exception in thread &#8220;main&#8221; Process completed successfully<\/p>\n<p>&nbsp;<\/p>\n<p>Udskriften viser tydeligt, at exception\u2019en f\u00f8rst opst\u00e5r i ThrowException, hvorefter den sendes til testException, der er den native metode.<\/p>\n<p>&nbsp;<\/p>\n<p>Det, der nu er blevet gennemg\u00e5et, er imidlertid kun halvdelen af emnet omkring exceptions. Det kan jo ogs\u00e5 ske, at den native metode f\u00e5r brug for at lade en exception opst\u00e5 og blive sendt tilbage til den kaldende metode. Nedenst\u00e5ende kode viser definitionen af en Java-klasse, der indeholder en native metode, der genererer en exception.<\/p>\n<p>&nbsp;<\/p>\n<p>public class ExceptionCreator<\/p>\n<p>{<\/p>\n<p>public native void create() throws NullPointerException;<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;Creator&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>javah-programmet genererer f\u00f8lgende headerfil baseret p\u00e5 ovenst\u00e5ende klassefil.<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class ExceptionCreator *\/<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_ExceptionCreator<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>#define _Included_ExceptionCreator<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 ExceptionCreator<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 create<\/p>\n<p>* Signature: ()V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_ExceptionCreator_create<\/p>\n<p>(JNIEnv *, jobject);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>C++-programmet skal implementere funktionen, der blot opretter en exception. Exceptions i Java er som bekendt objekter af en given klasse, og f\u00f8rste punkt i at oprette en exception er s\u00e5ledes at oprette en reference til exception-klassen. Det g\u00f8r man ved hj\u00e6lp af funktionen FindClass. Hvis denne funktion returnerer andet end 0, betyder det, at klassen blev fundet. Herefter kan man generere en ny exception ved at bruge funktionen ThrowNew. I kaldet til ThrowNew kan man blandt andet angive den tekst, exception\u2019en skal indeholde. Nedenst\u00e5ende C++-program genererer en exception:<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;exceptioncreator.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_ExceptionCreator_create (JNIEnv *env, jobject me)<\/p>\n<p>{<\/p>\n<p>jclass exception = env-&gt;FindClass(&#8220;java\/lang\/NullPointerException&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>if (!exception) \/\/ Klassen kunne ikke findes<\/p>\n<p>return;<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ThrowNew (exception, &#8220;C++ programmer kan ogs\u00e5 lave exceptions&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen CreatorApp kan bruges til at afpr\u00f8ve ExceptionCreator-klassen.<\/p>\n<p>&nbsp;<\/p>\n<p>public class CreatorApp<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[]) throws Exception<\/p>\n<p>{<\/p>\n<p>new ExceptionCreator().create();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Programmet giver f\u00f8lgende udskrift:<\/p>\n<p>&nbsp;<\/p>\n<p>java.lang.NullPointerException: C++ programmer kan ogs\u00e5 lave exceptions<\/p>\n<p>&nbsp;<\/p>\n<p>at ExceptionCreator.create(Native Method)<\/p>\n<p>at CreatorApp.main(CreatorApp.java:5)<\/p>\n<p>&nbsp;<\/p>\n<p>Der er nu blevet gennemg\u00e5et tilstr\u00e6kkeligt meget af JNI til, at der kan vises et eksempel. Der vil her blive set p\u00e5, hvordan man kan bruge Windows INI-filer fra Java.<\/p>\n<p><script type=\"text\/javascript\"><!--\ngoogle_ad_client = \"ca-pub-3400894606969585\";\n\/* Bibliotek - ajp *\/\ngoogle_ad_slot = \"3560879290\";\ngoogle_ad_width = 336;\ngoogle_ad_height = 280;\n\/\/-->\n<\/script><br \/>\n<script type=\"text\/javascript\"\nsrc=\"http:\/\/pagead2.googlesyndication.com\/pagead\/show_ads.js\">\n<\/script><\/p>\n<p>&nbsp;<\/p>\n<h1>INI-filer<\/h1>\n<p>&nbsp;<\/p>\n<p>I Windows API findes der en r\u00e6kke funktioner, som giver adgang til INI-filer. INI-filerne minder meget om Javas property-filer og har den f\u00f8lgende opbygning:<\/p>\n<p>&nbsp;<\/p>\n<p>[sektion]<\/p>\n<p>n\u00f8gle = v\u00e6rdi<\/p>\n<p>&nbsp;<\/p>\n<p>M\u00e6ngden af funktioner, der kan bruges til at manipulere med disse filer, er stor, og de vil ikke alle blive inkluderet i dette eksempel. Eksemplet vil kun give mulighed for at skrive og l\u00e6se en streng og for at skrive og l\u00e6se en integer. Det g\u00f8r man ved hj\u00e6lp af Windows-funktionerne WritePrivateProfileString, GetPrivateProfileString og GetPrivateProfileInt. Som det ses, findes der ikke nogen funktion til at skrive en integer. Det g\u00f8r man ved hj\u00e6lp af WritePrivateProfileString. Hver af funktionerne har en parameter, der angiver navnet p\u00e5 INI-filen. Dette er ikke s\u00e6rligt objektorienteret, og derfor bliver det lavet om i Java-klassen. Her angives filnavnet kun \u00e9n gang \u2013 i constructoren. Java-klassen, der stiller funktionaliteten til r\u00e5dighed, ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>public class IniFile<\/p>\n<p>{<\/p>\n<p>private String filename;<\/p>\n<p>&nbsp;<\/p>\n<p>private String getFilename ()<\/p>\n<p>{<\/p>\n<p>return filename;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public IniFile (String filename)<\/p>\n<p>{<\/p>\n<p>this.filename = filename;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public native void writeString (String section, String key, String value);<\/p>\n<p>public native String readString\u00a0 (String section, String key) throws KeyNotFoundException;<\/p>\n<p>&nbsp;<\/p>\n<p>public native void writeInteger (String section, String key, int value);<\/p>\n<p>&nbsp;<\/p>\n<p>public native int readInteger (String section, String key) throws KeyNotFoundException;<\/p>\n<p>&nbsp;<\/p>\n<p>static<\/p>\n<p>{<\/p>\n<p>System.loadLibrary (&#8220;ini&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>I de to read-funktioner kan der opst\u00e5 en KeyNotFoundException. Det sker, hvis den n\u00f8gle, man s\u00f8ger efter, ikke findes. De oprindelige funktioner i Windows API\u2019et giver ikke mulighed for exceptions. Ved at skrive en Java-klasse rundt om operativsystemfunktioner opn\u00e5r man alts\u00e5 ikke bare adgang til funktionerne, man har ogs\u00e5 mulighed for at give dem et mere objektorienteret design.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen KeyNotFoundException er defineret specielt til brug ved IniFile-klassen. Det er en almindelig excpetion-klasse, der ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>public class KeyNotFoundException extends Exception<\/p>\n<p>{<\/p>\n<p>public KeyNotFoundException ()<\/p>\n<p>{<\/p>\n<p>super();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>public KeyNotFoundException (String besked)<\/p>\n<p>{<\/p>\n<p>super (besked);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Da IniFile indeholder native metoder, skal der oprettes en headerfil baseret p\u00e5 den. Programmet javah genererer f\u00f8lgende headerfil:<\/p>\n<p>&nbsp;<\/p>\n<p>\/* DO NOT EDIT THIS FILE &#8211; it is machine generated *\/<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>\/* Header for class IniFile *\/<\/p>\n<p>&nbsp;<\/p>\n<p>#ifndef _Included_IniFile<\/p>\n<p>#define _Included_IniFile<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>extern &#8220;C&#8221; {<\/p>\n<p>#endif<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 IniFile<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 readInteger<\/p>\n<p>* Signature: (Ljava\/lang\/String;Ljava\/lang\/String;)I<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT jint JNICALL Java_IniFile_readInteger<\/p>\n<p>(JNIEnv *, jobject, jstring, jstring);<\/p>\n<p>&nbsp;<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 IniFile<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 readString<\/p>\n<p>&nbsp;<\/p>\n<p>* Signature: (Ljava\/lang\/String;Ljava\/lang\/String;)Ljava\/lang\/String;<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT jstring JNICALL Java_IniFile_readString<\/p>\n<p>(JNIEnv *, jobject, jstring, jstring);<\/p>\n<p>&nbsp;<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 IniFile<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 writeInteger<\/p>\n<p>* Signature: (Ljava\/lang\/String;Ljava\/lang\/String;I)V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_IniFile_writeInteger<\/p>\n<p>(JNIEnv *, jobject, jstring, jstring, jint);<\/p>\n<p>&nbsp;<\/p>\n<p>\/*<\/p>\n<p>* Class:\u00a0\u00a0\u00a0\u00a0 IniFile<\/p>\n<p>* Method:\u00a0\u00a0\u00a0 writeString<\/p>\n<p>* Signature: (Ljava\/lang\/String;Ljava\/lang\/String;Ljava\/lang\/String;)V<\/p>\n<p>*\/<\/p>\n<p>JNIEXPORT void JNICALL Java_IniFile_writeString<\/p>\n<p>(JNIEnv *, jobject, jstring, jstring, jstring);<\/p>\n<p>&nbsp;<\/p>\n<p>#ifdef __cplusplus<\/p>\n<p>}<\/p>\n<p>#endif<\/p>\n<p>#endif<\/p>\n<p>&nbsp;<\/p>\n<p>Headerfilen indeholder signaturerne p\u00e5 alle native metoder i klassen. Bem\u00e6rk, at javah sorterer funktionerne i alfabetisk orden. Af den grund vil r\u00e6kkef\u00f8lgen af funktionerne i C++-implementeringen v\u00e6re anderledes end i Java-programmet. Det er naturligvis programm\u00f8rens eget valg, hvilken r\u00e6kkef\u00f8lge funktionerne skal implementeres i.<\/p>\n<p>&nbsp;<\/p>\n<p>For at f\u00e5 adgang til de \u00f8nskede funktioner fra Windows-API\u2019et, skal man inkludere flere filer end vanligt. Det betyder, at #include-delen af C++-programmet kommer til at se s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;windows.h&gt;<\/p>\n<p>#include &lt;winbase.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>#include &#8220;IniFile.h&#8221;<\/p>\n<p>&nbsp;<\/p>\n<p>De to f\u00f8rste filer \u2013 windows.h og winbase.h \u2013 giver adgang til API-funktionerne, mens jni.h giver adgang til JNI-systemet. IniFile.h er den headerfil, der blev genereret af javah.<\/p>\n<p>&nbsp;<\/p>\n<p>Den f\u00f8rste funktion i C++-programmet er readInteger, der kommer til at hedde Java_IniFile_readInteger:<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT jint JNICALL Java_IniFile_readInteger (JNIEnv *env, jobject me, jstring section, jstring key)<\/p>\n<p>{<\/p>\n<p>\/\/ Find filnavnet<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>jclass classname = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID id = env-&gt;GetMethodID (classname, &#8220;getFilename&#8221;, &#8220;()Ljava\/lang\/String;&#8221;);<\/p>\n<p>jstring filename = (jstring) env-&gt;CallObjectMethod (me,id);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter Java-strenge til tekststrenge<\/p>\n<p>&nbsp;<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>const char *sction = env-&gt;GetStringUTFChars (section, 0);<\/p>\n<p>const char *k = env-&gt;GetStringUTFChars (key, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ L\u00e6s ini-filen<\/p>\n<p>&nbsp;<\/p>\n<p>int result = GetPrivateProfileInt (sction, k, -1234, fname);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Kontroller om v\u00e6rdien fandtes<\/p>\n<p>&nbsp;<\/p>\n<p>if (result == -1234)<\/p>\n<p>{<\/p>\n<p>jclass exception = env-&gt;FindClass(&#8220;KeyNotFoundException&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>if (!exception)<\/p>\n<p>return result;<\/p>\n<p>&nbsp;<\/p>\n<p>char exceptiontext[256];<\/p>\n<p>sprintf (exceptiontext,&#8221;V\u00e6rdien %s i sektionen [%s] findes ikke i filen %s&#8221;, k, sction, fname);<\/p>\n<p>env-&gt;ThrowNew (exception, exceptiontext);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Frigiv hukommelse<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ReleaseStringUTFChars (filename, fname);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (section, sction);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (key, k);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Returner resultatet<\/p>\n<p>&nbsp;<\/p>\n<p>return result;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Funktionens f\u00f8rste opgave er at finde navnet p\u00e5 den fil, der skal bruges. Det sker ved at kalde Java-metoden getFilename. Som vist tidligere, kalder man en Java-metode ved f\u00f8rst at lave en reference til klassen, dern\u00e6st en reference til metoden, hvorefter metodekaldet kan udf\u00f8res. Da getFilename returnerer String, der som bekendt er et objekt, skal metoden CallObjectMethod bruges. Denne returnerer naturligvis et jobject \u2013 dette skal efterf\u00f8lgende castes til jstring.<\/p>\n<p>&nbsp;<\/p>\n<p>Den n\u00e6ste opgave i funktionen er at konvertere de forskellige jstring til<\/p>\n<p>&nbsp;<\/p>\n<p>char-arrays, s\u00e5 de kan bruges i C++. N\u00e5r dette er p\u00e5 plads, kan kaldet til API-funktionen foretages. Den mystiske parameter \u2013 -1234 \u2013 er en <em>default v\u00e6rdi<\/em>, der returneres, hvis n\u00f8glen ikke kunne findes. Den returnerede v\u00e6rdi sammenlignes med denne \u2013 er de ens, betyder det alts\u00e5, at n\u00f8glen ikke fandtes, og derfor laves en KeyNotFoundException. Kan klassen KeyNotFoundException ikke findes, returnerer funktionen.<\/p>\n<p>&nbsp;<\/p>\n<p>Er alt g\u00e5et godt indtil videre, kan funktionen frigive den hukommelse, der er blevet l\u00e5st af tekststrengene. Herefter kan resultatet returneres.<\/p>\n<p>&nbsp;<\/p>\n<p>Java-funktionen readString bliver i C++ kaldt java_IniFile_readString og ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT jstring JNICALL Java_IniFile_readString (JNIEnv *env, jobject me, jstring section, jstring key)<\/p>\n<p>{<\/p>\n<p>\/\/ Find filnavnet<\/p>\n<p>&nbsp;<\/p>\n<p>jclass classname = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID id = env-&gt;GetMethodID (classname, &#8220;getFilename&#8221;, &#8220;()Ljava\/lang\/String;&#8221;);<\/p>\n<p>jstring filename = (jstring) env-&gt;CallObjectMethod (me,id);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter Java-strenge til tekststrenge<\/p>\n<p>&nbsp;<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>const char *sction = env-&gt;GetStringUTFChars (section, 0);<\/p>\n<p>const char *k = env-&gt;GetStringUTFChars (key, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ L\u00e6s ini-filen<\/p>\n<p>&nbsp;<\/p>\n<p>const char *defaultstring = &#8220;StandardV\u00e6rdi&#8221;;<\/p>\n<p>char result[1024];<\/p>\n<p>&nbsp;<\/p>\n<p>GetPrivateProfileString (sction, k, defaultstring, result, sizeof (result), fname);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Kontroller om v\u00e6rdien fandtes<\/p>\n<p>&nbsp;<\/p>\n<p>if (!strcmp (defaultstring, result))<\/p>\n<p>{<\/p>\n<p>jclass exception = env-&gt;FindClass(&#8220;KeyNotFoundException&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>if (!exception)<\/p>\n<p>return NULL;<\/p>\n<p>&nbsp;<\/p>\n<p>char exceptiontext[256];<\/p>\n<p>sprintf (exceptiontext,&#8221;V\u00e6rdien %s i sektionen [%s] findes ikke i filen %s&#8221;, k, sction, fname);<\/p>\n<p>env-&gt;ThrowNew (exception, exceptiontext);<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Frigiv hukommelse<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ReleaseStringUTFChars (filename, fname);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (section, sction);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (key, k);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Returner resultatet<\/p>\n<p>&nbsp;<\/p>\n<p>return env-&gt;NewStringUTF (result);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Funktionen starter \u2013 ligesom den foreg\u00e5ende \u2013 med at finde navnet p\u00e5 INI-filen, og konvertere tekststrenge. Kaldet til API\u2019et er imidlertid anderledes. Igen skal der gives en defaultv\u00e6rdi med i funktionskaldet. Da det er en streng, der fors\u00f8ges indl\u00e6st, skal defaultv\u00e6rdien naturligvis ogs\u00e5 v\u00e6re en streng. Til at modtage den fundne streng bliver der oprettet et char-array ved navn result. Sammenligningen af det modtagne resultat og defaultv\u00e6rdien sker ved hj\u00e6lp af strcmp\u00ad-funktionen, der returnerer nul, hvis teksterne er ens. Er dette tilf\u00e6ldet, oprettes en KeyNotFoundException efter samme opskrift som i readInteger-metoden.<\/p>\n<p>&nbsp;<\/p>\n<p>Herefter frigiver funktionen hukommelsen og er klar til at returnere resultatet. Dette skal imidlertid f\u00f8rst konverteres, da det er af typen char *, og funktionen returnerer en jstring. Konverteringen sker ved hj\u00e6lp af JNI\u2019s funktion NewStringUTF.<\/p>\n<p>&nbsp;<\/p>\n<p>Der er ikke meget ved at have l\u00e6sefunktioner, hvis ikke man ogs\u00e5 har skrivefunktioner. Den f\u00f8rste \u2013 WriteString \u2013 er defineret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_IniFile_writeString (JNIEnv *env, jobject me, jstring section, jstring key, jstring value)<\/p>\n<p>{<\/p>\n<p>\/\/ Find filnavnet<\/p>\n<p>&nbsp;<\/p>\n<p>jclass classname = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID id = env-&gt;GetMethodID (classname, &#8220;getFilename&#8221;, &#8220;()Ljava\/lang\/String;&#8221;);<\/p>\n<p>jstring filename = (jstring) env-&gt;CallObjectMethod (me,id);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter Java-strenge til tekststrenge<\/p>\n<p>&nbsp;<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>const char *sction = env-&gt;GetStringUTFChars (section, 0);<\/p>\n<p>const char *k = env-&gt;GetStringUTFChars (key, 0);<\/p>\n<p>const char *vlue = env-&gt;GetStringUTFChars (value, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Skriv ini-filen<\/p>\n<p>&nbsp;<\/p>\n<p>WritePrivateProfileString (sction, k, vlue, fname);<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Frigiv hukommelse<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ReleaseStringUTFChars (filename, fname);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;ReleaseStringUTFChars (section, sction);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (key, k);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (value, vlue);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Udover de parametre, de andre funktioner har, har skrivefunktionerne ogs\u00e5 en parameter, der angiver den v\u00e6rdi, der skal skrives.<\/p>\n<p>&nbsp;<\/p>\n<p>Igen starter funktionen med at hente filnavnet og konvertere tekststrenge. Dern\u00e6st skrives til INI-filen, hukommelsen frigives, og funktionen afsluttes. Hvis INI-filen ikke allerede eksisterer, vil den blive oprettet.<\/p>\n<p>&nbsp;<\/p>\n<p>Den anden skrivefunktion \u2013 writeInteger \u2013 er stort set identisk med writeString. Dog er der den kr\u00f8lle, at v\u00e6rdien skal konverteres fra en integer til en streng, da API\u2019et kun stiller WritePrivateProfileString\u00a0til r\u00e5dighed. Dette g\u00f8res ved hj\u00e6lp af sprintf-funktionen. writeString er implementeret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>JNIEXPORT void JNICALL Java_IniFile_writeInteger (JNIEnv *env, jobject me, jstring section, jstring key, jint value)<\/p>\n<p>{<\/p>\n<p>\/\/ Find filnavnet<\/p>\n<p>&nbsp;<\/p>\n<p>jclass classname = env-&gt;GetObjectClass (me);<\/p>\n<p>jmethodID id = env-&gt;GetMethodID (classname, &#8220;getFilename&#8221;, &#8220;()Ljava\/lang\/String;&#8221;);<\/p>\n<p>jstring filename = (jstring) env-&gt;CallObjectMethod (me,id);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Konverter Java-strenge til tekststrenge<\/p>\n<p>&nbsp;<\/p>\n<p>const char *fname = env-&gt;GetStringUTFChars (filename, 0);<\/p>\n<p>const char *sction = env-&gt;GetStringUTFChars (section, 0);<\/p>\n<p>const char *k = env-&gt;GetStringUTFChars (key, 0);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Skriv ini-filen<\/p>\n<p>&nbsp;<\/p>\n<p>char valuestring [128];<\/p>\n<p>sprintf (valuestring, &#8220;%i&#8221;, value);<\/p>\n<p>WritePrivateProfileString (sction, k, valuestring, fname);<\/p>\n<p>\/\/ Frigiv hukommelse<\/p>\n<p>env-&gt;ReleaseStringUTFChars (filename, fname);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (section, sction);<\/p>\n<p>env-&gt;ReleaseStringUTFChars (key, k);<\/p>\n<p>}<\/p>\n<p>N\u00e5r C++-filen er blevet kompileret til en DLL-fil, er systemet klar til brug. Nedenst\u00e5ende klasse \u2013 IniApp \u2013 viser, hvordan systemet kan bruges:<\/p>\n<p>public class IniApp<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>IniFile ini = new IniFile (&#8220;.\\\\test.ini&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;By: &#8221; + ini.readString (&#8220;Byer&#8221;, &#8220;7430&#8221;));<\/p>\n<p>}<\/p>\n<p>catch (KeyNotFoundException ex1)<\/p>\n<p>{<\/p>\n<p>System.err.println (ex1.toString());<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;Postnummer: &#8221; + ini.readInteger (&#8220;Postnumre&#8221;, &#8220;Ikast&#8221;));<\/p>\n<p>}<\/p>\n<p>catch (KeyNotFoundException ex2)<\/p>\n<p>{<\/p>\n<p>System.err.println (ex2.toString());<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>ini.writeString (&#8220;Byer&#8221;, &#8220;7430&#8221;, &#8220;Ikast&#8221;);<\/p>\n<p>ini.writeInteger (&#8220;Postnumre&#8221;, &#8220;Ikast&#8221;, 7430);<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;By: &#8221; + ini.readString (&#8220;Byer&#8221;, &#8220;7430&#8221;));<\/p>\n<p>}<\/p>\n<p>catch (KeyNotFoundException ex3)<\/p>\n<p>{<\/p>\n<p>System.err.println (ex3.toString());<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;Postnummer: &#8221; + ini.readInteger (&#8220;Postnumre&#8221;, &#8220;Ikast&#8221;));<\/p>\n<p>}<\/p>\n<p>catch (KeyNotFoundException ex4)<\/p>\n<p>{<\/p>\n<p>System.err.println (ex4.toString());<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Programmet starter med at instantiere et IniFile-objekt. Navnet p\u00e5 filen angives som .\\\\test.ini. At der skal angives et bibliotek, selvom filen skal ligge i det aktuelle bibliotek, skyldes, at Windows automatisk placerer INI-filer i Windows-bibliotek, hvis der ikke angives andet.<\/p>\n<p>&nbsp;<\/p>\n<p>Dern\u00e6st fors\u00f8ger programmet at indl\u00e6se en tekststreng fra n\u00f8glen 7430. Hvis denne ikke findes, opst\u00e5r en exception, der udskrives. Det samme g\u00f8r<\/p>\n<p>&nbsp;<\/p>\n<p>sig g\u00e6ldende, n\u00e5r programmet fors\u00f8ger en integer med n\u00f8glen Ikast.<\/p>\n<p>&nbsp;<\/p>\n<p>Herefter skriver programmet de to n\u00f8gler og indl\u00e6ser dem igen. Denne gang burde der ikke v\u00e6re nogen exceptions, da n\u00f8glerne jo netop er skrevet.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis filen test.ini ikke eksisterer, inden programmet udf\u00f8res, f\u00e5r man f\u00f8lgende udskrift:<\/p>\n<p>&nbsp;<\/p>\n<p>KeyNotFoundException: V\u00e6rdien 7430 i sektionen [Byer] findes ikke i filen .\\test.ini<\/p>\n<p>KeyNotFoundException: V\u00e6rdien Ikast i sektionen [Postnumre] findes ikke i filen .\\test.ini<\/p>\n<p>By: Ikast<\/p>\n<p>Postnummer: 7430<\/p>\n<p>&nbsp;<\/p>\n<p>Efter k\u00f8rsel af programmet er filen test.ini blevet oprettet. Filen har \u2013 som forventet \u2013 f\u00f8lgende indhold:<\/p>\n<p>&nbsp;<\/p>\n<p>[Byer]<\/p>\n<p>7430=Ikast<\/p>\n<p>&nbsp;<\/p>\n<p>[Postnumre]<\/p>\n<p>Ikast=7430<\/p>\n<p>&nbsp;<\/p>\n<h1>Tr\u00e5de<\/h1>\n<p>&nbsp;<\/p>\n<p>Java er som bekendt et flertr\u00e5det programmeringssprog. Dette g\u00e6lder ogs\u00e5, n\u00e5r man bruger native metoder, men der er nogle ting, man skal v\u00e6re opm\u00e6rksom p\u00e5.<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>JNIEnv-pointeren er kun gyldig i den aktuelle tr\u00e5d. Man m\u00e5 ikke overf\u00f8re JNIEnv-pointeren fra en tr\u00e5d til en anden.<\/li>\n<li>Man m\u00e5 ikke overf\u00f8re lokale variable fra en tr\u00e5d til en anden. En lokal variabel kan n\u00e5 at blive ugyldig, inden den modtagende tr\u00e5d f\u00e5r mulighed for at benytte den.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>I almindelige Java-programmer kan man nemt anvende Javas monitor til synkronisering. Dette kan eksempelvis g\u00f8res s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>synchronized (obj)<\/p>\n<p>{<\/p>\n<p>&#8230; \/\/ Kritisk region<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>S\u00e5 er det garanteret, at der ikke er andre tr\u00e5de, der l\u00e5ser obj. Man kan ikke forvente, at andre programmeringssprog stiller en monitor til r\u00e5dighed for programm\u00f8rerne \u2013 i s\u00e6rdeleshed g\u00f8r C++ ikke. Derfor har JNI-systemet to funktioner til at sikre synkronisering. Det drejer sig om funktionen MonitorEnter, der kaldes, n\u00e5r den programmet indtr\u00e6der i den kritiske region, og MonitorExit, der kaldes, n\u00e5r programmet forlader den kritiske region. Det betyder, at ovenst\u00e5ende Java-eksempel kan omformuleres til f\u00f8lgende C++-kode:<\/p>\n<p>env-&gt;MonitorEnter\u00a0(obj);<\/p>\n<p>&#8230;\u00a0 \/\/ Kritisk region<\/p>\n<p>env-&gt;MonitorExit (obj);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Tr\u00e5de benytter ogs\u00e5 metoder som wait, stop og notify. Disse er ikke umiddelbart tilg\u00e6ngelige i JNI-systemet, men man kan naturligvis bruge teknikkerne til at kalde en Java-metode som beskrevet tidligere i kapitlet.<\/p>\n<p>&nbsp;<\/p>\n<h1>Den virtuelle Java-maskine<\/h1>\n<p>&nbsp;<\/p>\n<p>Fra og med JDK version 1.1 bliver den virtuelle Java-maskine leveret som en DLL-fil. Det betyder, at man fra andre ikke-Java-programmer kan tilg\u00e5 den virtuelle maskine ved blot at kalde metoder i DLL\u2019en. Faktisk er programmet java, der bruges til at afvikle Java-programmer, ikke mere end et C-program, der behandler parametrene og kalder den virtuelle maskine gennem DLL-filen.<\/p>\n<p>&nbsp;<\/p>\n<p>Fra C++ kan man foretage kaldene til DLL\u2019en gennem jni.h-filen. Det f\u00f8rste, man skal g\u00f8re, er at hente standardindstillingerne for den virtuelle maskine \u2013 herefter kan man tilpasse dem, s\u00e5 de passer til ens eget form\u00e5l. Funktionskaldet, der henter indstillinger, har \u00e9t parameter \u2013 det er en struktur, der indeholder indstillingerne. Koden, der henter indstillingerne for den virtuelle Java-maskine, ser s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>JDK1_1InitArgs vm_args;<\/p>\n<p>JNI_GetDefaultJavaVMInitArgs\u00a0(&amp;vm_args);<\/p>\n<p>&nbsp;<\/p>\n<p>Det pr\u00e6cise udseende af strukturen afh\u00e6nger s\u00e5vel af den platform, programmet afvikles p\u00e5, som af udbyderen af den enkelte Java-maskine. P\u00e5 Suns virtuelle Java-maskine til Windows 95 ser definitionen s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>typedef struct JDK1_1InitArgs {<\/p>\n<p>jint version;<\/p>\n<p>&nbsp;<\/p>\n<p>char **properties;<\/p>\n<p>jint checkSource;<\/p>\n<p>jint nativeStackSize;<\/p>\n<p>jint javaStackSize;<\/p>\n<p>jint minHeapSize;<\/p>\n<p>jint maxHeapSize;<\/p>\n<p>jint verifyMode;<\/p>\n<p>char *classpath;<\/p>\n<p>&nbsp;<\/p>\n<p>jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args);<\/p>\n<p>void (JNICALL *exit)(jint code);<\/p>\n<p>void (JNICALL *abort)();<\/p>\n<p>&nbsp;<\/p>\n<p>jint enableClassGC;<\/p>\n<p>jint enableVerboseGC;<\/p>\n<p>jint disableAsyncGC;<\/p>\n<p>jint verbose;<\/p>\n<p>jboolean debugging;<\/p>\n<p>jint debugPort;<\/p>\n<p>} JDK1_1InitArgs;<\/p>\n<p>&nbsp;<\/p>\n<p>Indholdet af strukturen kan \u00e6ndres efter behov.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Det n\u00e6ste punkt p\u00e5 listen er at oprette selve den virtuelle maskine. Det sker ved et kald af funktionen JNI_CreateJavaVM. Denne funktion tager tre parametre. Den f\u00f8rste er en reference til en javaVM-struktur. Den n\u00e6ste er en reference til en JNIEnv-struktur, mens den sidste er de argumenter, JNI_GetDefaultJavaVMInitArgs\u00a0returnerede. De to f\u00f8rste parametre bruges til at gemme returv\u00e6rdier i. Funktionen returnerer en jint. Er denne mindre end 0, er der opst\u00e5et en fejl.<\/p>\n<p>&nbsp;<\/p>\n<p>Koden, der opretter den virtuelle Java-maskine, kan se s\u00e5ledes ud:<\/p>\n<p>&nbsp;<\/p>\n<p>JavaVM *javamaskine;<\/p>\n<p>JNIEnv *env;<\/p>\n<p>jint resultat;<\/p>\n<p>resultat = JNI_CreateJavaVM (&amp;javamaskine, &amp;env, &amp;vm_args);<\/p>\n<p>if (resultat &lt; 0)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Java-maskinen kunne ikke oprettes.&#8221;);<\/p>\n<p>exit(1);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man foretager et kald til JNI_CreateJavaVM, bliver den tr\u00e5d, der foretager kaldet, automatisk oprettet i den virtuelle maskine som en native metode. Den JNIEnv-pointer, der modtages ved kaldet af JNI_CreateJavaVM, svarer til den pointer, der normalt bliver overf\u00f8rt som parameter til native metoder. Man skal dog v\u00e6re opm\u00e6rksom p\u00e5, at programmer, der selv starter den virtuelle maskine, ikke har mulighed for at returnere til den virtuelle maskine ligesom ordin\u00e6re native metoder. Det betyder, at lokale variable ikke bliver frigivet, f\u00f8r man selv frigiver dem.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r den virtuelle maskine er startet, kan man kalde Java-metoder p\u00e5 samme m\u00e5de som fra native metoder. N\u00e5r man kompilerer sit C++-program, skal man huske at inkludere filen jvm.lib. Derudover skal filen jvm.dll v\u00e6re tilg\u00e6ngelig for programmet, n\u00e5r det afvikles. jvm.lib kan findes i biblioteket lib under Java-installationen, mens jvm.dll kan findes i bin\\classic.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende eksempel viser, hvordan man kan bruge JNI til at starte et Java-program.<\/p>\n<p>&nbsp;<\/p>\n<p>#include &lt;jni.h&gt;<\/p>\n<p>#include &lt;malloc.h&gt;<\/p>\n<p>&nbsp;<\/p>\n<p>int main (int argc, char *argv[])<\/p>\n<p>{<\/p>\n<p>\/\/ Kontroller syntaks<\/p>\n<p>&nbsp;<\/p>\n<p>if (argc != 2)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Syntaks: JavaVM &lt;klasse&gt;&#8221;);<\/p>\n<p>return 1;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Lokale variable<\/p>\n<p>&nbsp;<\/p>\n<p>JDK1_1InitArgs vm_args;<\/p>\n<p>&nbsp;<\/p>\n<p>JavaVM *javamaskine;<\/p>\n<p>JNIEnv *env;<\/p>\n<p>jclass theclass;<\/p>\n<p>jmethodID methodID;<\/p>\n<p>char classpath[1024];<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Hent standardindstillinger<\/p>\n<p>&nbsp;<\/p>\n<p>JNI_GetDefaultJavaVMInitArgs (&amp;vm_args);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Indstil classpath<\/p>\n<p>sprintf (classpath, &#8220;%s;.;c:\\\\programmer\\\\jdk12\\\\lib\\\\classes.zip&#8221;, vm_args.classpath);<\/p>\n<p>vm_args.classpath = classpath;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Opret Java-maskine<\/p>\n<p>&nbsp;<\/p>\n<p>jint resultat = JNI_CreateJavaVM (&amp;javamaskine, &amp;env, &amp;vm_args);<\/p>\n<p>&nbsp;<\/p>\n<p>if (resultat &lt; 0)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Java-maskinen kunne ikke oprettes.&#8221;);<\/p>\n<p>return 2;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Find den klasse, der skal udf\u00f8res<\/p>\n<p>&nbsp;<\/p>\n<p>theclass = env-&gt;FindClass (argv[1]);<\/p>\n<p>if (!theclass)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Klassen %s kunne ikke findes.&#8221;, argv[1]);<\/p>\n<p>return 3;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Find main-metoden<\/p>\n<p>&nbsp;<\/p>\n<p>methodID = env-&gt;GetStaticMethodID (theclass, &#8220;main&#8221;, &#8220;([Ljava\/lang\/String;)V&#8221;);<\/p>\n<p>if (!methodID)<\/p>\n<p>{<\/p>\n<p>printf (&#8220;Klassen %s har ikke en korrekt defineret main-metode.&#8221;);<\/p>\n<p>return 4;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Kald main-metoden<\/p>\n<p>&nbsp;<\/p>\n<p>env-&gt;CallStaticVoidMethod (theclass, methodID);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Afslut programmet<\/p>\n<p>&nbsp;<\/p>\n<p>return 0;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Programmet starter med at kontrollere, at det bliver kaldt med den rigtige syntaks. Den rigtige syntaks er JavaVM <em>klasse<\/em>. Dern\u00e6st bliver der oprettet en r\u00e6kke lokale variabler, der skal bruges senere i programmet. Herefter bliver standardindstillinger for den virtuelle Java-maskine hentet, og classpath bliver sat.<\/p>\n<p>&nbsp;<\/p>\n<p>Det f\u00f8rste parameter til programmet er som bekendt den klasse, der skal udf\u00f8res, og derfor er det denne klasse, der fors\u00f8ges fundet med FindClass-funktionen. Herefter findes den statiske main-metodes ID, og funktionen kaldes uden parametre. I dets nuv\u00e6rende form underst\u00f8tter JavaVM-programmet ikke, at der skal gives parametre med til main-metoden.<\/p>\n<p>&nbsp;<\/p>\n<h1>Sammenfatning<\/h1>\n<p>&nbsp;<\/p>\n<p>I dette kapitel er det blevet gennemg\u00e5et, hvordan man bruger Javas Native Interface. Det er blevet forklaret, hvordan man ved hj\u00e6lp af javah-programmet kan oprette headerfiler, der g\u00f8r det let at implementere funktioner i C og C++. Derudover er det blevet gennemg\u00e5et, hvordan man kalder Java-metoder fra native metoder, ligesom h\u00e5ndteringen af Java-objekter og variable samt exceptions er blevet beskrevet. Disse emner er blevet belyst yderligere gennem et eksempel, hvor det blev vist, hvordan man kunne bruge Windows API til at tilg\u00e5 INI-filer fra Java.<\/p>\n<p>&nbsp;<\/p>\n<p>Endeligt har kapitlet beskrevet, hvordan man gennem JNIEnv-pointeren kan opn\u00e5 synkronisering, og hvordan JNI kan bruges til at skrive en virtuel Java-maskine.<\/p>\n<p>&nbsp;<\/p>\n<h1>FAQ<\/h1>\n<p>&nbsp;<\/p>\n<h3>Hvorfor f\u00e5r jeg en java.lang.UnsatisfiedLinkError, n\u00e5r jeg pr\u00f8ver at k\u00f8re mit program?<\/h3>\n<p>&nbsp;<\/p>\n<p>Der kan v\u00e6re to grunde til, at man f\u00e5r en UnsatisfiedLinkError. Den ene er, at man har glemt den statiske blok, der indl\u00e6ser DLL-filen. Den anden er, at man ikke har sat sin <em>library path<\/em> rigtigt op. Library path\u00a0kan kun v\u00e6re et problem i Unix. I Windows s\u00f8ger loadLibrary-metoden efter DLL-filer de samme steder som Windows selv. Hvis man vil \u00e6ndre sin library path i Unix, kan det g\u00f8res med f\u00f8lgende kommando:<\/p>\n<p>% setenv LD_LIBRARY_PATH <em>sti<\/em><\/p>\n<h3>Er der forskel p\u00e5, hvordan JNI bruges fra C og C++<\/h3>\n<p>Ja. Selvom C og C++ p\u00e5 mange m\u00e5der minder om hinanden, er der forskel p\u00e5 den m\u00e5de, man kalder funktioner gennem JNIEnv-pointeren. I C++ kan man g\u00f8re det ved hj\u00e6lp af<\/p>\n<p>env-&gt;NewStringUTF\u00a0(&#8230;);<\/p>\n<p>&nbsp;<\/p>\n<p>mens man i C skal skrive<\/p>\n<p>&nbsp;<\/p>\n<p>(*env)-&gt;NewStringUTF (env, &#8230;);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3>Min headerfil ligner slet ikke de headerfiler, der er blevet vist her i kapitlet. Hvad er der galt?<\/h3>\n<p>&nbsp;<\/p>\n<p>Hvis man ikke husker \u2013jni-parametret, genererer javah-compileren ikke headerfiler til brug ved JNI.<\/p>\n<p>&nbsp;<\/p>\n<h3>Jeg bruger den samme DLL-fil i flere forskellige klasser. Beh\u00f8ver jeg at indl\u00e6se den i hver klasse?<\/h3>\n<p>&nbsp;<\/p>\n<p>Nej. Hvis man bruger den samme DLL-fil til at gemme funktionaliteten af flere klasser i, beh\u00f8ver man ikke at indl\u00e6se DLL\u2019en flere gang. Blot skal man v\u00e6re sikker p\u00e5, at alle klasserne indl\u00e6ses med den samme <em>class loader<\/em>.<\/p>\n<p>&nbsp;<\/p>\n<h3>Hvordan overf\u00f8res parametre fra Java til native metoder?<\/h3>\n<p>&nbsp;<\/p>\n<p>Parametre overf\u00f8res p\u00e5 pr\u00e6cis samme m\u00e5de som ved almindelige funktionskald i Java. Det vil sige, at primitive typer kopieres, mens objekter overf\u00f8res som referencer.<\/p>\n<p>&nbsp;<\/p>\n<h3>Hvordan sender man en exception videre til den Java-metode, der kaldte den native metode?<\/h3>\n<p>&nbsp;<\/p>\n<p>Hvis man returnerer fra en native metode, mens exceptionOccured er forskellig fra 0, vil den exception, der er opst\u00e5et, men endnu ikke h\u00e5ndteret, blive sendt videre til den Java-metode, der kaldte den native metode. Her vil exception\u2019en opst\u00e5 ligesom en almindelig Java-exception.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"border: 1px solid red; color: red\">\n<b>Du l\u00e6ser en gammel bog<\/b><br \/>\nDen bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\"  target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" \/>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":332,"menu_order":0,"comment_status":"closed","ping_status":"open","template":"","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"class_list":["post-413","page","type-page","status-publish","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"keywords\" content=\"java,jni,native interface,java native interface,c,c++,c#,header,exception\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Biblioteket | Samling af artikler og b\u00f8ger\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Java Native Interface (JNI) | Biblioteket\" \/>\n\t\t<meta property=\"og:description\" content=\"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2011-11-03T12:59:17+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2011-11-03T13:00:05+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Java Native Interface (JNI) | Biblioteket\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"position\":2,\"name\":\"B\\u00f8ger\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"position\":3,\"name\":\"Avanceret Java-programmering\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/#listItem\",\"name\":\"Kapitel 9 Java Native Interface (JNI)\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/#listItem\",\"position\":4,\"name\":\"Kapitel 9 Java Native Interface (JNI)\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/#webpage\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/\",\"name\":\"Java Native Interface (JNI) | Biblioteket\",\"description\":\"Et af de kritikpunkter, der er blevet fremf\\u00f8rt mod Java, er dets platformsuafh\\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\\u00f8rste forcer, er der mange, der mener, at det begr\\u00e6nser programm\\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\\u00f8tter de funktioner, som underst\\u00f8ttes af alle operativsystemer. Tidligere har is\\u00e6r brugergr\\u00e6nsefladen v\\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\\u00e5dighed, end Java kan udnytte. For at kunne tilg\\u00e5 disse funktioner, m\\u00e5 man benytte Java Native Interface (JNI).\",\"inLanguage\":\"da-DK\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-9-java-native-interface-jni\\\/#breadcrumblist\"},\"datePublished\":\"2011-11-03T14:59:17+02:00\",\"dateModified\":\"2011-11-03T15:00:05+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"inLanguage\":\"da-DK\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Java Native Interface (JNI) | Biblioteket","description":"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).","canonical_url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/","robots":"max-image-preview:large","keywords":"java,jni,native interface,java native interface,c,c++,c#,header,exception","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BreadcrumbList","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","position":1,"name":"Home","item":"https:\/\/www.kristiansborg.dk\/bibliotek","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","position":2,"name":"B\u00f8ger","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","position":3,"name":"Avanceret Java-programmering","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/#listItem","name":"Kapitel 9 Java Native Interface (JNI)"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/#listItem","position":4,"name":"Kapitel 9 Java Native Interface (JNI)","previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"}}]},{"@type":"Organization","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/"},{"@type":"WebPage","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/#webpage","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/","name":"Java Native Interface (JNI) | Biblioteket","description":"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).","inLanguage":"da-DK","isPartOf":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website"},"breadcrumb":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/#breadcrumblist"},"datePublished":"2011-11-03T14:59:17+02:00","dateModified":"2011-11-03T15:00:05+02:00"},{"@type":"WebSite","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","inLanguage":"da-DK","publisher":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization"}}]},"og:locale":"da_DK","og:site_name":"Biblioteket | Samling af artikler og b\u00f8ger","og:type":"article","og:title":"Java Native Interface (JNI) | Biblioteket","og:description":"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).","og:url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/","article:published_time":"2011-11-03T12:59:17+00:00","article:modified_time":"2011-11-03T13:00:05+00:00","twitter:card":"summary","twitter:title":"Java Native Interface (JNI) | Biblioteket","twitter:description":"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI)."},"aioseo_meta_data":{"post_id":"413","title":"Java Native Interface (JNI) | #site_title","description":"Et af de kritikpunkter, der er blevet fremf\u00f8rt mod Java, er dets platformsuafh\u00e6ngighed. Selvom dette samtidigt er blandt Javas st\u00f8rste forcer, er der mange, der mener, at det begr\u00e6nser programm\u00f8rens muligheder. Det skyldes blandt andet den opfattelse, at Java kun underst\u00f8tter de funktioner, som underst\u00f8ttes af alle operativsystemer. Tidligere har is\u00e6r brugergr\u00e6nsefladen v\u00e6ret skydeskive for megen kritik, da Windows indeholdt mange komponenter, der ikke kunne anvendes fra Java. Dette er blevet v\u00e6sentligt forbedret med Swing. Der er imidlertid stadig en r\u00e6kke punkter, hvor operativsystemet stiller flere funktioner til r\u00e5dighed, end Java kan udnytte. For at kunne tilg\u00e5 disse funktioner, m\u00e5 man benytte Java Native Interface (JNI).","keywords":[{"label":"Java","value":"Java"},{"label":"JNI","value":"JNI"},{"label":"Native Interface","value":"Native Interface"},{"label":"Java Native Interface","value":"Java Native Interface"},{"label":"C","value":"C"},{"label":"C++","value":"C++"},{"label":"c#","value":"c#"},{"label":"header","value":"header"},{"label":"exception","value":"exception"}],"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2020-12-21 06:59:15","updated":"2025-06-04 02:18:22","seo_analyzer_scan_date":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/\" title=\"B\u00f8ger\">B\u00f8ger<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/\" title=\"Avanceret Java-programmering\">Avanceret Java-programmering<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tKapitel 9 Java Native Interface (JNI)\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.kristiansborg.dk\/bibliotek"},{"label":"B\u00f8ger","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/"},{"label":"Avanceret Java-programmering","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/"},{"label":"Kapitel 9 Java Native Interface (JNI)","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-9-java-native-interface-jni\/"}],"_links":{"self":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/comments?post=413"}],"version-history":[{"count":2,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/413\/revisions"}],"predecessor-version":[{"id":415,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/413\/revisions\/415"}],"up":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/332"}],"wp:attachment":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/media?parent=413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}