Java本地接口

JNI （Java Native Interface，Java本地接口）是一种编程框架，使得Java虚拟机中的Java程序可以调用本地应用/或库，也可以被其他程序调用。 本地程序一般是用其它语言（C、C++或汇编语言等）编写的，并且被编译为基于本机硬件和操作系统的程序。
设计目的和功能.
有些事情Java无法处理时，JNI允许程序员用其他编程语言来解决，例如，Java标准库不支持的平台相关功能或者程序库。也用于改造已存在的用其它语言写的程序，供Java程序调用。许多基于JNI的标准库提供了很多功能给程序员使用，例如文件I/O、音频相关的功能。当然，也有各种高性能的程序，以及平台相关的API实现，允许所有Java应用程序安全并且平台独立地使用这些功能。 
JNI框架允许Native方法调用Java对象，就像Java程序访问Native对象一样方便。Native方法可以创建Java对象，读取这些对象，并调用Java对象执行某些方法。当然Native方法也可以读取由Java程序自身创建的对象，并调用这些对象的方法。
JNI如何工作.
在JNI框架，native方法一般在单独的.c或.cpp文件中实现。当JVM调用这些函数，就传递一个codice_1指针，一个codice_2的指针，任何在Java方法中声明的Java参数。一个JNI函数看起来类似这样： 
<syntaxhighlight lang="c">
JNIEXPORT void JNICALL Java_ClassName_MethodName
</syntaxhighlight>
"codice_3"指向一个结构包含了到JVM的界面，包含了所有必须的函数与JVM交互、访问Java对象。例如，把本地数组转换为Java数组的JNI函数，把本地字符串转换为Java字符串的JNI函数，实例化对象，抛出异常等。基本上，Java程序可以做的任何事情都可以用codice_1做到，虽然相当不容易。 
例如，下面代码把Java字符串转化为本地字符串：
<syntaxhighlight lang="cpp">
//C++ code
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
</syntaxhighlight>
<syntaxhighlight lang="c">
/*C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName
</syntaxhighlight>
<syntaxhighlight lang="objc">
/*Objective-C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName
</syntaxhighlight>
本地数据类型与Java数据类型可以互相映射。对于复合数据类型，如对象，数组，字符串，就必须用codice_1中的方法来显示地转换。
第2个参数"obj"引用到一个Java对象，在其中声明了本地方法。 
类型映射.
下表是Java (JNI)与本地代码之间的数据类型映射：
签名codice_6是由该名字指明的类。例如，签名codice_7是类codice_8。带前缀codice_9的签名表示该类型的数组，如codice_10表示整型数组。codice_11签名使用codice_12代码。
这些类型是可以互换的，如codice_13也可使用 codice_14，不需任何类型转换。
但是，Java字符串、数组与本地字符串、数组是不同的。如果在使用codice_15代替了codice_16，程序可能会导致JVM崩溃。
<syntaxhighlight lang="cpp">
JNIEXPORT void JNICALL Java_ClassName_MethodName
</syntaxhighlight>
这种情况也适用于Java数组。下例对数组元素求和。
<syntaxhighlight lang="cpp">
JNIEXPORT jint JNICALL Java_IntArray_sumArray
</syntaxhighlight>
JNIEnv*.
JNI环境指针(JNIEnv*)作为每个映射为Java方法的本地函数的第一个参数，使得本地函数可以与JNI环境交互。这个JNI界面指针可以存储，但仅在当前线程中有效。其它线程必须首先调用AttachCurrentThread()把自身附加到虚拟机以获得JNI界面指针。一旦附加，本地线程运行就类似执行本地函数的正常Java线程。本地线程直到执行DetachCurrentThread()把自身脱离虚拟机。
把当前线程附加到虚拟机并获取JNI界面指针：
当前线程脱离虚拟机：
高级使用.
本地AWT绘制.
本地代码不仅可以与Java交互，也可以在Java 绘图，使用。 
访问汇编代码.
JNI允许直接访问汇编代码。 也可以从汇编代码访问Java。
Microsoft的RNI.
Microsoft实现的Java虚拟机——Visual J++的类似的访问本地Windows代码的机制Raw Native Interface（RNI）。 
例子.
HelloWorld.
make.sh
<syntaxhighlight lang="bash">
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
javac HelloWorld.java
javah HelloWorld
gcc -shared libHelloWorld.c -o libHelloWorld.so
java HelloWorld
</syntaxhighlight>
build.bat
<syntaxhighlight lang="dos">
SET VC="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC"
SET MSDK="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A"
SET JAVA_HOME="C:\Program Files (x86)\Java\jdk1.7.0_21"
call %VC%\vcvarsall.bat
javac HelloWorld.java
javah HelloWorld
%VC%\bin\cl /I%JAVA_HOME%\include /I%JAVA_HOME%\include\win32 /I%VC%\include /I%VC%\lib /I%MSDK%\Lib libHelloWorld.c /FelibHelloWorld.dll /LD
java HelloWorld
</syntaxhighlight>
HelloWorld.java
<syntaxhighlight lang="java">
class HelloWorld
 private native void print();
 public static void main(String[] args)
 new HelloWorld().print();
 static{
 System.loadLibrary("HelloWorld");
</syntaxhighlight>
HelloWorld.h
<syntaxhighlight lang="c">
/* DO NOT EDIT THIS FILE - it is machine generated */
/* Header for class HelloWorld */
extern "C" {
JNIEXPORT void JNICALL Java_HelloWorld_print
</syntaxhighlight>
libHelloWorld.c
<syntaxhighlight lang="c">
</syntaxhighlight>
Invocation:
<syntaxhighlight lang="bash">
$ chmod +x make.sh
$ ./make.sh
</syntaxhighlight>