JNI快速入门
来源:互联网 发布:淘宝客服招聘 可在家 编辑:程序博客网 时间:2024/06/05 14:08
JNI快速入门
JNI为Java Native Interface 即Java本地接口,使用此种机制可以实现Java和C/C++互相调用.本文对该机制进行快速入门,
并记录了我在整个过程中遇到的问题及解决方法。
Java调用C++代码
Java调用C++代码本质上是对C++生成的动态库进行调用而不是直接对C/C++代码进行调用。
第一步:设计Java端接口;
public class HelloJNI {/** * @param args Native关键字 */ private native void printMsg(); public static void main(String[] args) {// TODO Auto-generated method stub new HelloJNI().printMsg();} static { //静态代码块中的代码加载dll,保证该类的dll文件只被加载一次 System.loadLibrary("HelloJNI"); }}
命令行编译:javac HelloWorld.java
第二步:使用javah工具生成C++接口文件.
Javah HelloJNI 生成文件HelloJNI.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloJNI */#ifndef _Included_HelloJNI#define _Included_HelloJNI#ifdef __cplusplusextern "C" {#endif/* * Class: HelloJNI * Method: printMsg * Signature: ()V 方法签名:用来映射C++function Java_HelloJNI_printMsg和Java function printMsg的参数和返回值可以使用命令:[ javap -s -private 类名] 来查看方法签名参数说明:JNIEnv* :JNI环境指针.该指针为JVM当前中当前线程的句柄,包含一些映射信息和管理信息Jobject :调用该本地方法的方法的引用,如果调用方法(本地方法调用者)是静态方法,该参数将是jclass类型 */JNIEXPORT void JNICALL Java_HelloJNI_printMsg (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
参数说明:
JNIEnv* :JNI环境指针.该指针为JVM当前中当前线程的句柄,包含一些映射信息和管理信息
Jobject :调用该本地方法的方法的引用,如果调用方法(本地方法调用者)是静态方法,该参数将是jclass类型
关于方法签名多说几句:
这时HelloJNI的方法签名,其意义见下表:
类型签名的意义:
第三步:根据HelloJNI.h头文件创建动态链接库。具体步骤为:
1 新建VC6.0动态链接库工程HelloJNI
2 将HelloJNI.h头文件copy到工程目录下,这是比较偷懒的做法,比较好的做法是创建一个文件来存放自己外部的头文件,
在项目中指定路径projetct->setting->C++->processor->additional include directoryes:
3 在工程中HelloJNI.cpp文件中导入必须的头文件
#include "jni.h"
#include "HelloJNI.h"
Jin.h头文件在jdk安装目录下的include文件夹,如果找不到,使用2中的方式包含该路径。
Ok,HelloJNI.h的实现文件为HelloJNI.cpp
#include "jni.h" //这里不要用#include <jin.h>#include "HelloJNI.h"BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ return TRUE;}JNIEXPORT void JNICALL Java_HelloJNI_printMsg (JNIEnv * env, jobject obj){ //简单的测试语句,打印jdk版本,打印出的是一个Long值jint versionid = env->GetVersion();printf("jdk version:%d",versionid);}
第四步:编译HelloJNI工程,生成HelloJNI.dll动态链接库文件,生成的dll文件会在debug文件夹或者release文件夹中;
第五步:继续用偷懒的办法来看运行效果,把第四步生成的HelloJNI.dll文件copy到和HelloJNI.class同一目录下
命令行执行:java HelloJNI
C++调用Java代码
C++调用Java代码的原理是在C++代码中创建JVM,加载class文件然后执行。
下面来简单入门。
第一步:创建HelloCPP.java文件.
class HelloCPP{public void printHello(){System.out.println("hello C++");}}
注意,这个类现在是裸奔的,没有加马甲(package).
命令行执行命令:javac HelloCPP.java
生成HelloCPP.class
第二步:VC6.0创建Win32 console工程CppCallJavaDemo
// CppCallJavaDemo.cpp : Defines the entry point for the console application.//#include "jni.h"// 环境变量PATH在windows下和linux下的分割符定义#ifdef _WIN32#define PATH_SEPARATOR ';'#else#define PATH_SEPARATOR ':'#endifint main(int argc, char* argv[]){JavaVMOption options[1];JNIEnv *env;JavaVM *jvm;JavaVMInitArgs vm_args;long status;jclass jcls;jmethodID mid;jobject obj;options[0].optionString = "-Djava.class.path=."; //这里声明类的寻找路径,可以有过个路径 //"."表示工程工程目录//options[1].optionString = "-Djava.class.path=H:\\project\\CPPCallJava"; //memset(&vm_args,0,sizeof(vm_args));vm_args.version=JNI_VERSION_1_6;vm_args.nOptions=1;vm_args.options = options;//获得虚拟机,从返回值判断是否成功 我在测试过程中遇到的返回参数是 0 -1 -3/*#define JNI_OK 0 success 成功#define JNI_ERR (-1) unknown error 未知错误,返回这个参数就难以判断问题所在了#define JNI_EDETACHED (-2) thread detached from the VM JVM的派生线程#define JNI_EVERSION (-3) JNI version error JNI版本不一致,返回这个参数就需要判断jvm与JNI是否版本一致#define JNI_ENOMEM (-4) not enough memory 内存不够#define JNI_EEXIST (-5) VM already created 已经创建了JVM#define JNI_EINVAL (-6) invalid arguments 参数不正确*/status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if(!env){ printf("env is null!\r\n");}if(status != JNI_ERR){//根据类名找到类 jcls =env->FindClass("HelloCPP"); //类加了package需要这样查找,包名以"/"分开 // jcls =env->FindClass("test/HelloCPP");if(jcls != NULL){ //获得methodid 参数分别为 jclass 调用方法名 方法签名 signature //使用javap -s -private 类名 查看方法签名mid = env->GetMethodID(jcls,"printHello","()V");//创建对象//obj = env->AllocObject(jcls);//获得默认构造方法的id jmethodID constid =env->GetMethodID(jcls,"<init>","()V");//根据默认构造方法创建对象obj = env->NewObject(jcls,constid);printf("method id:%d\r\n",mid);if(mid != 0){env->CallVoidMethod(obj,mid);}printf("get object!!\r\n");}else{printf("not get object!!\r\n");}}jvm->DestroyJavaVM();return 0;}
运行结果:
好了,要是这些代码跑起来还有一些工作要做!
首先为了保证编译通过,需要配置jin.h文件路径
该文件在jdk安装目录下的Include包中
然后需要配置jin.Lib文件路径,该路径在jdk安装目录下的lib包中
Project->setting->link->input->additional library path:
还有就是我们需要的jvm.dll文件了,在jre/bin/server/目录下可以找到它,把它配到环境变量中。
OK,这样就可以运行exe了!
在整个过程中遇到了两个问题。
Q1:创建JVM失败,无赖的是返回的Statue是-1,表示是未知错误,多方检查才发现是JVM.dll用错了,刚开始配的是/jre/bin/client目录下的jvm.dll,
改正之后成功创建JVM.
Q2:找不到类。
这个问题困扰了我好一阵子。
首先是一遍遍检查了配置,没问题。依然找不到类。直觉告诉我肯定是类的路径不对。
于是我尝试了多个路径,把编译生成的HelloCPP.class文件置于各个目录下,依然找不到了。
后来我把类中的马甲(package test;刚开始是有这个马甲的)去掉了,把class文件放到工程目录下,bingo!!
如果给类加了马甲,那么在工程目录下需要创建实体目录才行。
如马甲为packate test;
那么在工程目录下新建文件夹test,然后将class文件置于其中,也可以找到类。
到此做了简单入门。网上有一些参考资料,这里可以下载本文中的演示例子以及一些JNI相关资料:demo下载
- JNI快速入门
- jni快速入门
- JNI快速入门手册
- JNI快速入门
- OpenCV4Android+JNI开发快速上手入门
- JNI之C语言(一)--快速入门
- 一天掌握Android JNI本地编程 快速入门
- JNI入门
- JNI入门
- JNI入门
- JNI入门
- JNI 入门
- JNI入门
- JNI入门
- JNI入门
- JNI入门
- jni入门
- JNI入门
- WPF窗口如何获得一个句柄?
- Java多线程(十二)之线程池深入分析(下)
- html中简单的script实例
- JVM调优总结
- 图的遍历--思想
- JNI快速入门
- delphi对复杂泛型排序学习笔记
- WCHAR char CString等常用类型互转
- UNICODE十六进制数组转成中英文
- android实现3D效果翻页
- oracle row_number over
- P6spy + sqlprofiler -持久化动态监测框架
- 最大公约数和最小公倍数求法 C++
- 经典alsa 录音和播放程序