Java Native Interface
Java Native Interface o JNI (letteralmente interfaccia nativa Java) è il nome di un framework di programmazione che ha lo scopo di permettere ad applicazioni Java di interfacciarsi con funzioni scritte in altri linguaggi di programmazione, in particolare C, C++ e assembly.
L'uso principale di JNI consiste nel consentire a programmi Java di far uso di servizi implementati tramite codice nativo del sistema operativo per il quale si sta scrivendo il programma.
L'interfacciamento è basato sulla definizione di un insieme di classi di raccordo fra i due contesti, che presentano una interfaccia Java, ma che delegano al codice nativo l'implementazione dei loro metodi. Lo stesso framework consente anche l'operazione inversa, ovvero l'invocazione di codice Java da parte di programmi scritti nei linguaggi nativi.
Il mapping effettuato, ovviamente, dipende dal linguaggio nativo scelto; ad esempio, se si fa uso del C, ad ogni metodo della classe corrisponderà una funzione di libreria con un nome ben preciso.
Utilizzo di JNI
Una classe può definire un numero arbitrario di metodi implementati in codice nativo. Per far questo, nel sorgente della classe il metodo deve avere la parola-chiave native e deve avere un punto e virgola al posto del corpo del metodo. Ad esempio:
public class Classe {
public void metodo() { /* ... */ }
public native void metodoNativo();
}
Come si evince dall'esempio, non è necessario che la classe abbia solo metodi nativi.
Un metodo native può essere statico o di istanza; esso può essere final o meno. Non ha senso definire un metodo nativo come abstract.
Uso dei metodi nativi
In genere, i metodi nativi vengono mantenuti privati dalla classe che li definisce, mentre dei metodi pubblici o protected (invocati dai clients o dalle sottoclassi) fungono da wrappers. In accordo con il principio dell'incapsulamento delle informazioni, questo consente di definire un'interfaccia per la classe che sia completamente indipendente dall'uso del codice nativo; in questo modo, sarà più facile in futuro modificare il comportamento della classe mantenendo un'interfaccia nativa retrocompatibile con le librerie native già implementate.
Applicazioni pratiche
Il JNI viene principalmente utilizzato per consentire al programma l'accesso a funzioni definite nelle librerie del sistema operativo ospite mediante primitive di sistema. In realtà, l'accesso avviene in modo indiretto, nel senso che le funzioni del sistema operativo vengono invocate dalle funzioni che implementano i metodi nativi della classe che li definisce e che vengono a loro volta utilizzati dal codice Java.
L'uso del JNI si rende inoltre necessario quando l'implementazione di una certa funzionalità nel programma dipende dal sistema operativo in uso a run-time e non è presente nelle librerie standard di Java. Il programma risultante non può essere definito "100%-Java", in quanto esso fa direttamente uso di codice nativo.
Nell'implementazione Sun delle librerie standard della piattaforma Java, sono molti i metodi native. L'implementazione di questi metodi è presente solo nella macchina virtuale che verrà utilizzata a run-time.
Vantaggi/Svantaggi
L'utilizzo del JNI limita la portabilità del programma all'insieme delle piattaforme per le quali è realmente presente un'implementazione della libreria nativa. Questo significa che la classe che fa uso di metodi nativi non potrà essere utilizzata su tutti i sistemi per i quali è presente un Java Runtime Environment. Di fatto, un programma che faccia uso di classi con metodi nativi non può essere definito "100% Java".
Per questo motivo, è consigliabile utilizzare JNI solo se strettamente necessario o se il programma verrà utilizzato unicamente su un numero limitato di piattaforme specifiche.
Le librerie standard sono un'eccezione: l'implementazione dei metodi nativi da esse definiti è (necessariamente) presente in ogni virtual machine e spesso è addirittura necessaria per la corretta esecuzione del programma stesso.