JNI

JNI (Java Native Interface) é uma interface inclusa na JDK (Java Development Toolkit) para definir métodos nativos e embutir a Máquina Virtual Java dentro de aplicações nativas. Métodos nativos são funções escritas em linguagens como C, C++ e até mesmo Assembly, compiladas em DLLs (Windows) ou so's (Linux e Solaris). JNI serve como uma ponte entre Java e a parte nativa de uma aplicação, provendo funcionalidades para comunicação entre ambas as partes. Também estão incluídas na JDK ferramentas para mapear protótipos de métodos e tipos de dados de Java para C / C++.

Nem sempre é recomendável utilizar JNI, já que um dos principais benefícios de Java, a portabilidade, não existe: é necessário recompilar a implementação nativa em cada sistema operacional onde a aplicação será executada. A complexidade da aplicação aumenta razoavelmente, ainda mais por que não há mecanismos para liberação automática de memória (coleta de lixo).

Os usos mais indicados são:

  • Implementação de uma porção crítica de uma aplicação, com requisitos de melhor desempenho. Devemos que lembrar que Java é uma linguagem interpretada e por isso com desempenho inferior a código compilado
  • Acesso a bibliotecas nativas e sistemas legados, onde não há possibilidade ou interesse de reimplementá-los. Na atividade em que estive envolvido (veja), essa foi a principal motivação

Exemplo:

public class Teste {
    public native void displayHelloWorld();
}

A diretiva native indica que a implementação do método é nativa. A ferramenta javah gera um arquivo .h com o protótipo da função a ser definida em C ou C++:

#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Após a definição da função e compilação em uma DLL (ou .so) ou método pode ser invocado:

System.loadLibrary("hello");
new HelloWorld().displayHelloWorld();

hello.dll (ou hello.so) é carregado na memória e o método é invocado.