首页 > 代码库 > JNI简易教程,windows and linux
JNI简易教程,windows and linux
关于各种原理,jni和jna对比什么的请自行百度,这里仅介绍一下基本使用方法,方便初学者,也给自己留一份笔记而已。
1~3介绍jni的使用流程,4示例了java中string和byte[]与c++的类型转换,5简单介绍了native方法定义为static的相关问题
简单说一下jni的使用流程就像一个圆,从java出发,声明你需要的native方法,生成一个对应的.h文件,根据这个h文件构造c/c++工程生成dll/so动态库,最后返回来给java调用。
首先要注意的是,要分开windows,linux,x32,x64。我是没有去捣鼓跨平台做这个jni,在什么平台用就统一用什么平台开发吧,linux上的eclipse-java工程就在linux上做c++工程生成.so动态库,windows上的就在vs上做c++工程生成.dll动态库。
1:
废话不多说,无论是windows还是linux,打开你的eclipse建一个java project,我习惯这样的目录结构
LibTest.java:
1 package jni_lib; 2 3 public class LibTest { 4 static { 5 System.loadLibrary("jni_lib_LibTest"); 6 } 7 8 public native static void HelloWorld(String i_instr); 9 }
JniTest.java:
1 package test; 2 3 import jni_lib.LibTest; 4 5 public class JniTest { 6 public static void main(String[] args) { 7 LibTest.HelloWorld(new String("I‘m Nycko")); 8 } 9 }
到这里java的代码可以说是全部写完了,当main方法执行时,将调用LibTest的HelloWorld方法,该方法的实现来自于jni_lib_LibTest.dll(libjni_lib_LibTest.so)中,那么这个工程现在缺少的就是这个动态库了,下面来生成这个动态库。
2:
无论是windows还是linux,你需要确保命令行可以运行javac,不行的自行百度安装jdk并且设置环境变量。下面以windows演示,linux的javac和javah命令用法一致,列出目录windows用dir,linux用ls
在定义native的.java文件目录下用javac编译该文件获得.class文件。
然后前往该项目的bin目录,用javah处理刚才生成的.class文件,这里javah后面跟的不是路径,而是java中的包名+类名。
就会生成一个.h文件,该文件官方建议不要修改哦~,我们根据这个.h文件构建一个c/c++工程生成对应的动态库。
jni_lib_LibTest.h:
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class jni_lib_LibTest */ 4 5 #ifndef _Included_jni_lib_LibTest 6 #define _Included_jni_lib_LibTest 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: jni_lib_LibTest 12 * Method: HelloWorld 13 * Signature: (Ljava/lang/String;)V 14 */ 15 JNIEXPORT void JNICALL Java_jni_1lib_LibTest_HelloWorld 16 (JNIEnv *, jclass, jstring); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
3:
(windows)在visual studio中新建项目,选择visual c++的win32控制台应用程序,点击下一步然后应用程序类型改选为DLL,完成。
(linux)linux下新建一个工程不就是新建一个目录这么简单吗,哈哈,新建一个jni_lib_LibTest.cpp,不一定这个名字啦。
把步骤2中的.h文件拷贝到项目中,然后编写c++文件
jni_lib_LibTest.cpp:函数名从.h文件中拷贝过来,然后参数类型后面需要添加你的变量名。像jstring这样的类型从java传过来无法直接当作c++的string使用,大部分变量都需要jni的方法做转换,这里先介绍jni的工序,更详细的代码实现先忽略。
// jni_lib_LibTest.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h"
//linux不要加这个文件
#include "jni_lib_LibTest.h" #include <iostream> using namespace std; /* * Class: jni_lib_LibTest * Method: HelloWorld * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_jni_1lib_LibTest_HelloWorld (JNIEnv *env, jclass, jstring j_i_inStr) { char* i_inStr; i_inStr = const_cast<char*>(env->GetStringUTFChars(j_i_inStr, false)); if (i_inStr == NULL) { cout << "i_inStr == NULl!" << endl; return ; /* OutOfMemoryError already thrown */ } cout << "OutPut in jni_lib_LibTest.cpp!" << endl; cout << "Helloworld! i_inStr is : " << i_inStr << endl; env->ReleaseStringUTFChars(j_i_inStr, i_inStr); }
(windows)然后就可以点击(生成->生成解决方案),生成相应的.dll动态库了,编译不通过的话看一下错误是什么咯,有可能遇到的问题是工程的SDK,include路径等等的属性设置问题,我使用了SDK=10.0.14393.0,附加包含目录=%JAVA_HOME%\include;%JAVA_HOME%\include\win32;%(AdditionalIncludeDirectories)。具体问题具体分析,自行解决哦~。另外要注意的是32和64位的问题,64位的java工程当然对应64位的动态库咯,我的机器是64的,java工程默认建出来是64所以这里vs生成的动态库选择x64来编译。
(linux)一句命令即可,简单
然后把这个.dll(.so)动态库放到java工程目录下,自定义你的目录结构吧。我在根目录下建了一个jnilib文件夹放dll(.so)文件。
如果现在运行java,还是报错,真心塞,原来还要修改一下配置,如图添加以下路径即可。
展开JRE System Library,双击 Native library location,选择你存放动态库的目录
然后就可以运行你的java程序了,还不行的话要检查一下windows下System.loadLibrary只需要写文件名前面,后缀.dll不需要写,linux下更是lib和.so都不要,只取中间的动态库名字即可。
输出如下:
4:介绍两个常用的类型转换
string获取:
char* str_cpp; str_cpp = const_cast<char*>(env->GetStringUTFChars(java_string, false)); if(str_cpp == NULL) { return NULL; /* OutOfMemoryError already thrown */ } //do something env->ReleaseStringUTFChars(java_string, str_cpp);
srting返回:
char* str; //do something return env->NewStringUTF(str);
byte[]获取:
int byte_len= env->GetArrayLength(java_byte ); BYTE* byte_value=http://www.mamicode.com/(BYTE*)(env->GetByteArrayElements(java_byte ,0));
byte[]返回:
int byte_len = 10; BYTE* byte_value=http://www.mamicode.com/new BYTE[10](); jbyteArray jarrRV = env->NewByteArray(byte_len); env->SetByteArrayRegion(jarrRV, 0, byte_len , (jbyte*)byte_value); return jarrRV;
5:关于java中native方法是否定义为static的问题:
JNI简易教程,windows and linux