1.什么是JNI
JNI是JavaNative Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++),通俗来说就是Java语言调用其他语言提供的接口。
2.什么是native方法
简单地讲,一个Native Method就是一个java调用非java代码的接口。一个NativeMethod是这样一个java的方法:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数。
3.实例
1)创建一个TestJni.java的文件
import java.util.*;
public class TestJni { //声明原生函数:参数为String类型 public native void print(String content);
//加载本地库代码 static { System.loadLibrary("TestJni"); } } |
注意print方法的声明,关键字native表明该方法的具体实现是在其他语言中(c&c++)实现的
另外注意static代码段的System.loadLibrary调用,这段代码表示在程序加载的时候,自动加载libTestJni.so库。
编译 TestJni.java文件:javac TestJni.java
在当前文件夹下生成TestJni.class文件
2)生成TestJni.h文件
执行命令:javah -jni TestJni
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class TestJni */
#ifndef _Included_TestJni
#define _Included_TestJni #ifdef __cplusplus extern "C" { #endif /* * Class: TestJni * Method: print * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_TestJni_print (JNIEnv *, jobject, jstring);
#ifdef __cplusplus } #endif #endif |
该文件中包含了一个函数Java_TestJni_print的声明。这里面自动包含两个非常重要的参数:JNIEnv*和jobject
3)创建TestJni.C文件
#include <jni.h> #include <stdio.h> #include <TestJni.h>
JNIEXPORT void JNICALL Java_TestJni_print(JNIEnv *env,jobject obj, jstring content) { // 从 instring字符串取得指向字符串 UTF编码的指针 //注意C语言必须(*env)-> C++ env-> const jbyte *str =(const jbyte *)(*env)->GetStringUTFChars(env,content, JNI_FALSE);
printf("Hello---->%s\n",str);
// 通知虚拟机本地代码不再需要通过 str访问 Java字符串。 (*env)->ReleaseStringUTFChars(env, content, (const char *)str );
return; } |
//jobject指向在此Java代码中实例化的 Java对象 LocalFunction的一个句柄,相当于 this指针
参数类型 jstring对应java中的String,这里是有所不同的。每一个Java里的类型这里有对应的与之匹配。
4)生成共享库
命令行输入:gcc-I/usr/lib/jvm/java-6-sun/include/linux/ -I/usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o libTestJni.so TestJni.c
执行完命令后会在当前目录生成liblibTestJni.so库文件,其功能就是有一个print函数与刚才所创建的TestJni.java文件对应,
TestJni.java类中加载库liblibTestJni.so,声明了其函数print,所以TestJni.java中具备使用print函数的功能
注意:
其中的选项-I/usr/lib/jvm/java-6-sun/include/linux/ -I/usr/lib/jvm/java-6-sun/include/ 是Java的include目录(请根据自己系统环境设定)
Linux下一个库的必须要是:lib+库名+.so。链接的时候只需要提供库名就可以了
5)创建HelloWorld.java文件
import java.util.*; public class HelloWorld { public static void main(String argv[]) { TestJni demon = new TestJni(); Demon.print(“world!”); }
} |
输入命令编译: javac HelloWorld.java,生成HelloWorld.class
6)运行
命令行输入:Java HelloWorld
4.JNI的副作用
一旦使用JNI,JAVA程序就丧失了JAVA平台的两个优点:
1、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
2、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和C之间的耦合性。