java调用C JNI方式调用DLL

Java调用C的操作流程:

1.java中声明一个本地方法(没有方法体)

一般本地方法写为static方法,因为只是调用本地方法实现逻辑,并不需要创建实例。关于本地方法的详细解释见http://blog.csdn.net/jiakw_1981/article/details/3073613。以下是本地方法的写法。


2.运用javah命令得到.h文件作为C的头文件

javah生成.h文件时

这两种方式都不行。这里需要了解一下javah几个选项的作用

正确的方法是,其中-d选项是用来指定,.h文件的生成位置

.h文件如下图


JNI(Java Native Interface)意为JAVA本地调用,它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。JNI详见http://blog.csdn.net/banketree/article/details/40535325

jni.h文件定义了JNIJava Native Interface)所支持的类型与接口。通过预编译命令可以支持CC++jni.h文件还依赖jni_md.h文件,jni_md.h文件定义了机器相关的jbyte, jintjlong对应的本地类型。

jni.h详见http://blog.csdn.net/taotaoyouarebaby/article/details/8751033

我的理解jni.h和jni_md.h就是在java调用c或者c++函数时,java本身的一种支撑接口,当中定义了一些函数,用来让C那边获取和操作java的对象,类,还定义了java和C之间可以互相通信的类型jint,jbyteArray,等等。

上面的红框中的函数定义对应上面的java本地方法,.h里方法名自动变成Java_包名_类名_方法名(参数列表)

参数列表中JNIEnv *  ,主要是用来操作java,他里面有很多成员函数可以操作java的环境。jclass是用来获取java的类。jint就是int4个字节,jbyteArray就是byte[]


3.创建DLL(动态链接库)

在Windows桌面下选择动态链接库,设定好项目名称和位置


4.用javah生成的.h文件作为头文件写出本地方法的具体实现


GetByteArrayElements函数作用作用是在C中开辟一块内存,将传入的byte[]拷贝到C的内存中,方便C后面用指针进行操作。这个函数的第二个参数可以是true,也可以是false。true表示不拷贝内存到C,用指针直接操作java的那块内存区,false表示先拷贝一份出来,C操作这份拷贝的内存,操作完再把这份内容复制到java内存中。这个函数执行过程中可能会改变isCopy的值,我一开始设的是false不拷贝,直接操作java内存,简单粗暴省内存,但是执行了这个函数后isCopy被改为了true,说明还是拷贝了。其实还是建议拷贝,因为java虚拟机其实很脆弱,它自己运作管理内存他可以管理的很好,但是一旦让外部的代码直接操作JVM分配好的内存是很危险的,因为一旦内存用超了,JVM立马就会崩溃。

ReleaseByteArrayElements函数就是把操作好的c内存复制给java,并把这块内存释放掉(java程序员调用C程序时要特别注意C代码中内存释放(踩坑血泪),C没有java的自动垃圾回收,必须用自己用代码回收)。我原本是用SetIntArrayRegion这个函数,这个函数也是把C内存复制给java,但是这个函数没有释放内存,导致JVM一直不能回收这块内存,最终容易造成堆栈溢出,JVM崩溃。

还有类似的函数操作不同类型的参数


备注:

1.javah生成的.h文件包含了jni.h,jni.h又包含了jni_md.h,  jni.h文件位于Java安装目录下的JDK1.6.023\include,jni_md.h文件位于JDK1.6.0 23\include\win32下,可以把这两个目录设为项目的包含目录,也可以直接把这两个文件直接放入头文件目录。

2.我刚接触VS,用的不熟练,踩坑的小细节还是总结总结吧

1.编译时无法找到include文件的问题

在cpp中写了include后,在项目的头文件添加.h文件。直接写include “.h文件名”这是在当前目录下找.h文件,这种情况下.h文件要和.c或者.cpp文件放在一块儿,编译的时候才能找到。但是这样会使项目文件看起来比较乱。可以在项目下新建一个include文件夹,把.h文件都放在里面,然后打开项目属性,在包含文件里添加上这个文件夹。我在用vs的时候也遇到过添加了包含文件后依然找不到.h,实在不行include的时候就写绝对路径吧,虽然看起来丑了点。。。。

2.extern int  rsa_encrypt(DIGIT_T *encrypt_key, DIGIT_T *trail_key, char *buff, int len);这是C里,要用别的文件里的函数时的写法,先extern引入,后面就可以直接用了。

3.java打好jar包(不是一般jar包,是可以运行的jar包,里面有main方法作为程序运行入口,相当于一个小程序,用eclipse的export直接可以打,当然控制台也可以打jar包,就是稍微麻烦点,运行jar命令java -jar  jar包路径),这里要讲的是打好了jar,在VS配好命令运行jar包,jar里调用了C生成的Dll,在调用的C文件中打上断点,理论上可以进到C程序中进行断点调试,时刻监控堆栈内存情况。这里说是理论上,是因为我并没有实现这样的调试,具体原因尚不明确,这里写下来是因为我觉得这个调试思路是可行的,为以后的调试提供一些想法,如果哪位大神java调用C的时候采用这种调试思路成功了请告诉我,如果这种想法是错的也请告诉我,谢谢了。


上面写的是java命令,写的是绝对路径,下面是选项和jar包路径

5.生成DLL文件

(根据自己需要选择32位还是64位)


6.设置java项目的本地library路径

就是你要调用的DLL文件放的位置,建议dll文件和java生成的.h文件放一起


6.java调用本地方法

调用本地方法之前要先加载dll文件,System.loadLibrary("kjdbc_jni");然后再调用。




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值