1.何为JNI?
JNI是JAVA标准平台中的一个重要功能,它弥补了JAVA的与平台无关这一重大优点的不足,在JAVA实现跨平台的同时,也能与其它语言(如C、C++)的动态库进行交互,给其它语言发挥优势的机会。有了JAVA标准平台的支持,使JNI模式更加易于实现和使用
这里不再赘述,附上别人总结的图:
知识补充:
存根类(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
/* 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++程序引用,引用时需改成
include "jni.h"
2)此头文件中的Java_com_magc_jni_HelloWorld_DisplayHello(JNIEnv *, jobject)方法,是将来与动态链接库交互的接口,并需要名字保持一致。
5.使用C/C++实现本地方法生成动态库文件(windows下扩展名为DDL,linux下扩展名为so):
程序代码如下:#include "stdafx.h"
#include "jni.h"
#include "com_magc_jni_HelloWorld.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++文件实现了上com_magc_jni_HelloWorld.h头文件中的函数,注意方法名要保持一致。
6. 生成DLL文件,运行HelloWorld.java程序
用visual studio 2015 生成DLL文件,具体怎么生成可参阅这篇博文
将生成的hello.dll文件复制到eclipse项目下,运行控制台成功输出