Java本地接口

设计目的和功能

JNI允许程序员用其他编程语言来解决用纯粹的Java代码不好处理的情况，例如，Java标准库不支持的平台相关功能或者程序库。也用于改造已存在的用其它语言写的程序，供Java程序调用。许多基于JNI的标准库提供了很多功能给程序员使用，例如文件I/O、音频相关的功能。当然，也有各种高性能的程序，以及平台相关的API实现，允许所有Java应用程序安全并且平台独立地使用这些功能。 
JNI框架允许Native方法调用Java对象，就像Java程序访问Native对象一样方便。Native方法可以创建Java对象，读取这些对象，并调用Java对象执行某些方法。当然Native方法也可以读取由Java程序自身创建的对象，并调用这些对象的方法。

JNI如何工作

在JNI框架，native方法一般在单独的.c或.cpp文件中实现。当JVM调用这些函数，就传递一个JNIEnv指针，一个jobject的指针，任何在Java方法中声明的Java参数。一个JNI函数看起来类似这样： 
JNIEXPORT void JNICALL Java_ClassName_MethodName
  (JNIEnv *env, jobject obj){
    /*Implement Native Method Here*/}
env指向一个结构包含了到JVM的界面，包含了所有必须的函数与JVM交互、访问Java对象。例如，把本地数组转换为Java数组的JNI函数，把本地字符串转换为Java字符串的JNI函数，实例化对象，抛出异常等。基本上，Java程序可以做的任何事情都可以用JNIEnv做到，虽然相当不容易。 
例如，下面代码把Java字符串转化为本地字符串：
//C++ codeextern "C"JNIEXPORT void JNICALL Java_ClassName_MethodName
  (JNIEnv *env, jobject obj, jstring javaString){
    //Get the native string from javaString
    const char *nativeString = env->GetStringUTFChars(javaString, 0);

    //Do something with the nativeString

    //DON'T FORGET THIS LINE!!!
    env->ReleaseStringUTFChars(javaString, nativeString);}
/*C code*/JNIEXPORT void JNICALL Java_ClassName_MethodName
  (JNIEnv *env, jobject obj, jstring javaString){
    /*Get the native string from javaString*/
    const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);

    /*Do something with the nativeString*/

    /*DON'T FORGET THIS LINE!!!*/
    (*env)->ReleaseStringUTFChars(env, javaString, nativeString);}
/*Objective-C code*/JNIEXPORT void JNICALL Java_ClassName_MethodName
  (JNIEnv *env, jobject obj, jstring javaString){
    /*DON'T FORGET THIS LINE!!!*/
    JNF_COCOA_ENTER(env);

    /*Get the native string from javaString*/
    NSString* nativeString = JNFJavaToNSString(env, javaString);

    /*Do something with the nativeString*/

    /*DON'T FORGET THIS LINE!!!*/
    JNF_COCOA_EXIT(env);}
本地数据类型与Java数据类型可以互相映射。对于复合数据类型，如对象，数组，字符串，就必须用JNIEnv中的方法来显示地转换。
第2个参数obj引用到一个Java对象，在其中声明了本地方法。

JNIEnv*

JNI环境指针(JNIEnv*)作为每个映射为Java方法的本地幔数的第一个参数，使得本地幔数可以与JNI环境交互。这个JNI界面指针可以存储，但仅在当前线程中有效。其它线程必须首先调用AttachCurrentThread()把自身附加到虚拟机以获得JNI界面指针。一旦附加，本地线程运行就类似执行本地幔数的正常Java线程。本地线程直到执行DetachCurrentThread()把自身脱离虚拟机。
把当前线程附加到虚拟机并获取JNI界面指针：
JNIEnv *env;
(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);
当前线程脱离虚拟机：
(*g_vm)->DetachCurrentThread (g_vm);

本地AWT绘制

本地代码不仅可以与Java交互，也可以在Java Canvas绘图，使用Java AWT Native Interface。

访问汇编代码

JNI允许直接访问汇编代码。 也可以从汇编代码访问Java。

Microsoft的RNI

Microsoft实现的Java虚拟机——Visual J++的类似的访问本地Windows代码的机制Raw Native Interface（RNI）。

HelloWorld

make.sh
#!/bin/sh# openbsd 4.9# gcc 4.2.1# openjdk 1.7.0export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
javac HelloWorld.java
javah HelloWorld
gcc -shared libHelloWorld.c -o libHelloWorld.so
java HelloWorld
build.bat
:: Microsoft Visual Studio 2012 Visual C++ compilerSET VC="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC":: Microsoft Windows SDK for Windows 7 and .NET Framework 4 SET MSDK="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A":: Java 1.7.0 update 21SET 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
HelloWorld.java
class HelloWorld{
private native void print();
public static void main(String[] args)
{
new HelloWorld().print();
}
static{
System.loadLibrary("HelloWorld");
}}
HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloWorld */#ifndef _Included_HelloWorld#define _Included_HelloWorld#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloWorld * Method:    print * Signature: ()V */JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
libHelloWorld.c
 #include <stdio.h>
 #include "HelloWorld.h"

 JNIEXPORT void JNICALL
 Java_HelloWorld_print(JNIEnv *env, jobject obj)
 {
     printf("Hello World!\n");
     return;
 }
Invocation:
$ chmod +x make.sh
$ ./make.sh