Java Native Interface

api binnen het Java platform

De Java Native Interface (JNI) is een API binnen het Java platform. De JNI is een interface tussen programma's geschreven in Java en programma's die opgesteld zijn in de instructietaal van de hardware waarop ook de Java Virtual Machine draait -- zogeheten native programma's.

Technische uitvoering bewerken

De JNI definieert een interface in twee richtingen tussen de JVM en externe code.

De eerste richting loopt van binnen de JVM naar code buiten de JVM en weer terug. Dit gebruik van de JNI bestaat eruit dat binnen een (of meer) klasse(n) een of meer methodes gedefinieerd worden die als native gemarkeerd worden. Een native methode binnen de JVM is impliciet abstract -- er is geen implementatie van in de JVM. Ter vervanging daarvan wordt een implementatie gegeven in een native programma dat gecompileerd wordt tot een dynamische bibliotheek voor het hardwareplatform onder de JVM. Deze bibliotheek wordt in het geheugen geladen door de JVM, op aangave van het programma dat de bibliotheek wenst te gebruiken. Het programma geeft dit aan de JVM aan door middel van een speciale opdracht (java.lang.Runtime.loadLibrary()), gegeven binnen een statisch blok en dus uitgevoerd op het moment dat de betreffende klasse ingeladen wordt.

De andere richting loopt van binnen een native programma naar de JVM en terug. In dit geval gebruikt het native programma de JNI om een instantie van de JVM in te laden en te starten en vervolgens die JVM-instantie om een Java-programma uit te voeren.

In beide gevallen voorziet de JNI in een brug tussen de JVM en native programma's die het mogelijk maakt om wederzijdse code uit te laten voeren. Deze brug bestaat vooral uit methodes om een klasse of methode in de geheugenruimte van de JVM aan te spreken en code uit te laten voeren, maar ook uit een mapping tussen de primitieve types die gedefinieerd zijn binnen de JVM en de primitieve types die bestaan in de programmeertaal waarin het native programma geschreven wordt. Via deze brug kan een native programma code aanroepen binnen de JVM of het resultaat van een berekening aan een JVM leveren. Voor communicatie in de andere richting bedient de JVM de mechanismen van de JNI en de in het Java programma gedefinieerde native methodes worden op dezelfde manier aangesproken als "normale" methodes.

Native code wordt normaal gesproken geschreven in een andere programmeertaal dan Java. Voor de zeer populaire talen als C en C++ bestaan standaard tools zoals javah die de programmeur ondersteunen bij het gebruik van de JNI door stukken native code te genereren, waarna alleen nog de eigenlijke implementatie ingevuld moet worden. Het ontbreken van dergelijke tools voor andere talen wil echter niet zeggen dat de JNI exclusief gericht is op de "ondersteunde" talen: iedere taal die native programma's kan genereren en dynamische bibliotheken aan kan spreken, kan gebruikt worden.

Voor- en nadelen bewerken

De JNI is al sinds het prille begin onderdeel van het Java platform. De JNI is geïntroduceerd om Java programma's toegang te geven tot faciliteiten waar de JVM en bestaande Java klassen geen directe toegang toe bieden.

Door middel van de JNI is het mogelijk om de mogelijkheden van een Java programma uit te breiden tot de mogelijkheden van de gehele computer, inclusief bijvoorbeeld toegang tot randapparatuur die niet direct ondersteund wordt door de JVM en de klassenbibliotheek. Ook is het met de JNI mogelijk om een JVM in te bedden in een native programma en gebruik te maken van alle faciliteiten van de Java klassenbibliotheek, of een klein Java programma snel uit te voeren (door een JVM te starten waarin niet alle klassen uit de klassenbibliotheek voorgeladen worden). Ook werd de JNI in de vroege dagen van Java genoemd als de geschikte methode om snelheidskritieke algoritmes te implementeren door gebruik te maken van het snelheidsvoordeel van native programma's op de onderliggende hardware. Dit laatste voordeel is met de komst van just in time compilers voor Java echter grotendeels verdwenen.

Tegenwoordig wordt de JNI minder en minder gebruikt en wordt het gebruik ervan ook meer en meer afgeraden tenzij het echt niet anders kan. Ontwikkelingen op het vlak van JVMs (de just in time compilers en HotSpot-compilers) hebben het snelheidsverschil van een lopend Java programma ten opzichte van een gelijk programma in native code verminderd. Daarentegen betekent het gebruik van de JNI wel dat een deel van het programma qua geheugengebruik niet gecontroleerd wordt door de JVM, wat tot geheugenlekken kan leiden. Bovendien is het vrij makkelijk om via native code (zeker wanneer deze geschreven wordt in C of C++) de geheugenruimte van de JVM te vervuilen en zo de hele JVM te laten crashen. Dit is een probleem voor een simpel programma op een simpele JVM, maar een zeer complexe installatie zoals een JVM binnen een applicatieserver is hier extra gevoelig voor -- een argument dat gebruik van JNI binnen de context van een J2EE-applicatie ontraadt.
Daarnaast bindt het gebruik van de JNI een Java programma niet alleen aan de JVM (de natuurlijke omgeving van een Java programma) maar ook aan de onderliggende hardware en vaak ook aan het besturingssysteem. Dit betekent dat een Java programma opeens niet meer zonder meer overdraagbaar is van JVM op JVM. Het kan ook betekenen dat een Java programma een update van het besturingssysteem op dezelfde hardware niet overleeft, als daarbij het formaat van de dynamische bibliotheken wijzigt.

De bovenstaande nadelen, plus het feit dat gangbare hardware meer en meer direct toegankelijk is voor Java programma's via de JVM, hebben ervoor gezorgd dat de JNI recentelijk minder en minder gebruikt wordt. De twee gebieden waar de JNI tegenwoordig voornamelijk wordt toegepast zijn ontwikkeling van specifieke software voor een specifieke doelgroep op een specifieke machine met bijzondere hardware-eisen (zoals ongewone hardware) en in interpreters voor scripttalen die het mogelijk willen maken om Java klassen te gebruiken in scripts. Voor deze laatste categorie wordt gewerkt aan een uitbreiding van het Java platform om de interactie tussen de JVM en interpreters te verbeteren, de zogeheten JSR-223.