1.何为JNI?
JNI是JAVA标准平台中的一个重要功能,它弥补了JAVA的与平台无关这一重大优点的不足,在JAVA实现跨平台的同时,也能与其它语言(如C、C++)的动态库进行交互,给其它语言发挥优势的机会。有了JAVA标准平台的支持,使JNI模式更加易于实现和使用
这里不再赘述,附上别人总结的图:
原图链接:http://www.cnblogs.com/mandroid/archive/2011/06/15/2081093.html
知识补充:
存根类(stub),它实现了一个接口,但是实现后的每个方法都是空的。
它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法。但是一个类从业务来说,可能只需要其中一两个方法。如果直接去实现这个接口,除了实现所需的方法,还要实现其他所有的无关方法。而如果通过继承存根类就实现接口,就免去了这种麻烦。
头文件
百度解释:一般会把用来#include的文件的扩展名叫.h,称其为头文件。 #include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体代码尺寸;或者提供跨工程公共代码。
2 javah
使用Javah 可以获取您的 Java 源文件并生成 C/C++头文件,其中包含您的 Java
代码中所有本地方法(native方法)的 JNI 存根(stub,C头文件)。
3.eclipse配置javah
JNI的编写步骤
a、编写带有native声明的方法的java类
b、使用javac命令编译a中实现的类
c、javah -jni java类名生成扩展名为h的头文件
d、使用C/C++实现本地方法
e、将d中的本地方法生成动态链接库
首先新建一个包含本地方法(native方法)的类,native标识符暗示这些方法是有实现体的,只不过这些实现体是非java的,代码如下:
/** * */ package com.magc.jni; /** * @author magc * */ public class HelloWorld { static { System.loadLibrary("Hello"); } public native void DisplayHello(); /** * @param args */ public static void main(String[] args) { new HelloWorld().DisplayHello(); } }
注:
load和loadLibrary区别
- 它们都可以用来装载库文件,不论是JNI库文件还是非JNI库文件。在任何本地方法被调用之前必须先用这个两个方法之一把相应的JNI库文件装载。
2.System.load
参数为库文件的绝对路径,可以是任意路径。
例如你可以这样载入一个windows平台下JNI库文件:
System.load("C:\\Documents
and Settings\\TestJNI.dll");3. System.loadLibrary
参数为库文件名,不包含库文件的扩展名。
例如你可以这样载入一个windows平台下JNI库文件
System. loadLibrary
("TestJNI");这里,TestJNI.dll
必须是在java.library.path这一jvm变量所指向的路径中。
可以通过如下方法来获得该变量的值:
System.getProperty("java.library.path");
默认情况下,在Windows平台下,该值包含如下位置:
1)和jre相关的一些目录
2)程序当前目录
3)Windows目录
4)系统目录(system32)
5)系统环境变量path指定目录。
classpath与java.library.path区别
classpath路径下,只能是jar或者class 文件,否者会报错,因为他们会被load到JVM中
要想java程序找到共享库还是要在执行java程序的时候指定java.library.path,用eclipse的话可以设置如下:
- Properties->Run/Debug settings->Arguments->VM arguments
- -----------------------------------------
- -Djava.library.path=/home/miaoyachun/workspace/JNIC/Release
需要使用外部工具,在我们运行java程序按钮的旁边,或者通过菜单栏上的run选项进入External
tool中并选择 External tool configuration,新建一个启动项HelloWorld
参数如下:
Location:
D:\program
files\Java\jdk1.7.0_51\bin\javah.exe
Working Directory
${project_loc}
Arguments:
-v -classpath "${project_loc}/bin" -d
"${project_loc}/jni" ${java_type_name} (这里v表示启用详细输出)
4.生成实现函数头文件(扩展名为h)
运行该工具,光标必须定位在在需要生成头文件的java源文件中,否则会报${project_loc}这个变量为空错误
在当前项目的jni目录下生成了com_magc_jni_HelloWorld.h头文件,此文件供C、C++程序来引用并实现其中的函数
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_magc_jni_HelloWorld */ #ifndef _Included_com_magc_jni_HelloWorld #define _Included_com_magc_jni_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: com_magc_jni_HelloWorld * Method: DisplayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_com_magc_jni_HelloWorld_DisplayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
注:1)、此头文件是不需要用户编译的,直接供其它C、C++程序引用。
2)、此头文件中的Java_com_magc_jni_HelloWorld_DisplayHello(JNIEnv *, jobject)方法,是将来与动态链接库交互的接口,并需要名字保持一致。
5.使用C/C++实现本地方法生成动态链接库(windows下扩展名为DDL,linux下扩展名为so):
#include <jni.h> #include "com_magc_jni_HelloWorld.h" #include <stdio.h> JNIEXPORT void JNICALL Java_com_magc_jni_HelloWorld_DisplayHello (JNIEnv *env, jobject obj) { printf("From jni_helloworldImpl.cpp :"); printf("Hello world ! \n"); return; }
此C++文件实现了上述头文件中的函数,注意方法函数名要保持一致。
编译生成动态链接库文件,有了具体实现的动态库,拷贝到项目的bin目录下,就可以运行JAVA调用JNI程序类的native方法了