在java中调用c语言——JNI入门
来源:互联网 发布:淘宝信用查询网站 编辑:程序博客网 时间:2024/05/18 13:25
本文章非原创,多数内容参考以下两篇博客,感谢。由于我在实践中遇到一些问题,所以打算做一些补充,重新写一篇更完整的JNI入门文章。
使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库
Java语言与C语言混合编程(1)--Java native 关键字
一、编写java文件:创建native method
简单地讲,一个 native Method 就是一个java调用非java代码的接口。表示一个方法的实现在java以外,已经在本地实现了。
如果想更加了解 native Method 可以查看 Java语言与C语言混合编程(1)--Java native 关键字。
下面我们举个例子。
package myJNI;public class myJNI { public native int intMethod(int n); public native boolean booleanMethod(boolean bool); public native String stringMethod(String text); public native int intArrayMethod(int[] intArray); public static void main(String[] args) { System.loadLibrary("myJNIdll");//注意: 不可以在代码中写上后缀 .dll 或 .so myJNI sample = new myJNI(); int square = sample.intMethod(5); boolean bool = sample.booleanMethod(true); String text = sample.stringMethod("Java"); int sum = sample.intArrayMethod(new int[]{1,2,3,4,5,8,13}); System.out.println("intMethod:" + square); System.out.println("booleanMethod:" + bool); System.out.println("stringMethod:" + text); System.out.println("intArrayMethod:" + sum); }}
上面有4个native方法, 4个native方法就是我们需要用C来实现的方法.
分别是4种类型的参数, int, boolean, String, int[].
其中有一句比较重要, 这句话加载了动态类库
System.loadLibrary("myJNI");
在windows下加载的就是myJNI.dll, 在Linux下加载的就是myJNI.so.
本文使用的windows, 所以后面使用myJNI.dll来表示myJNI动态链接库.
编译myJNI.java, 使用命令行(windows是cmd, linux下一般是bash)
javac myJNI.java
可以看到myJNI.class文件
二、使用javah生成头文件
javah myJNI.myJNI
注意带上包名,我们的文件一般有包名。我的例子里包名是myJNI,在Java文件里可以看到。这和java命令一样。平时IDE用多了容易忘记。
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class myJNI_myJNI */#ifndef _Included_myJNI_myJNI#define _Included_myJNI_myJNI#ifdef __cplusplusextern "C" {#endif/* * Class: myJNI_myJNI * Method: intMethod * Signature: (I)I */JNIEXPORT jint JNICALL Java_myJNI_myJNI_intMethod (JNIEnv *, jobject, jint);/* * Class: myJNI_myJNI * Method: booleanMethod * Signature: (Z)Z */JNIEXPORT jboolean JNICALL Java_myJNI_myJNI_booleanMethod (JNIEnv *, jobject, jboolean);/* * Class: myJNI_myJNI * Method: stringMethod * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_myJNI_myJNI_stringMethod (JNIEnv *, jobject, jstring);/* * Class: myJNI_myJNI * Method: intArrayMethod * Signature: ([I)I */JNIEXPORT jint JNICALL Java_myJNI_myJNI_intArrayMethod (JNIEnv *, jobject, jintArray);#ifdef __cplusplus}#endif#endif
我们可以看到其中有四个函数声明, Java_包名_完整类名_方法名, 完整类名包括了包名。
在注释中我们可以看到这样一个东西 Signature, 这个是方法的签名. 关于Signature, 下面通过一个表格来说明.
java类型Signature备注booleanZ byteB charC shortS intI longL floatF doubleD voidV objectL用/分割的完整类名例如: Ljava/lang/String表示String类型Array[签名例如: [I表示int数组, [Ljava/lang/String表示String数组Method(参数签名)返回类型签名例如: ([I)I表示参数类型为int数组, 返回int类型的方法上面头文件的第一个函数声明
JNIEXPORT jint JNICALL Java_myJNI_myJNI_intMethod (JNIEnv *, jobject, jint);
上方注释中的签名是 Signature: (I)I
在每个函数的参数列表中都有JNIEnv *和 jobject两个参数, 这两个参数稍候说明.
三、编辑DLL文件
1.处理头文件之间的联系
对 jni.h 文件做一些更改,#include <jni_md.h>改为 #include "C:\Program Files\Java\jdk1.8.0_101\include\win32\jni_md.h"
对我们用 javah 生成的头文件的开头部分 include 语句也要用双引号加文件名。自动生成的是如下样子,改为
#include "C:\Program Files\Java\jdk1.8.0_101\include\jni.h"
Java 的安装目录里。我们把这两个文件放到了我们的 DLL project 里,如果不用双引号将会差找不到。
深入学习的话去了解 include 语句。
include 关系为 dll.h include jni.h , jni.h include jni_md.h
也可以直接用 #include "jni_md.h" 和 #include "jni.h",要把这两个文件和dll.h放在一个目录下。
然后把我们生成的头文件 myJNI_myJNI.h 的内容全部复制粘贴到 dll.h 文件里,粘贴到下图中选中的位置。
为什么不直接用myJNI_myJNI.h 文件呢?因为如果没有上图里的那几句话,dll 文件是无法编译输出的。你也可以把这几句话
放进myJNI_myJNI.h 文件。
2.编写 c 程序
#include "dll.h"#include <string.h>JNIEXPORT jint JNICALL JNICALL Java_myJNI_myJNI_intMethod (JNIEnv *env, jobject obj, jint num){ return num * num;} JNIEXPORT jboolean JNICALL JNICALL Java_myJNI_myJNI_booleanMethod (JNIEnv *env, jobject obj, jboolean boolean){ return !boolean;} JNIEXPORT jstring JNICALL JNICALL Java_myJNI_myJNI_stringMethod (JNIEnv *env, jobject obj, jstring string){ const char* str = (*env)->GetStringUTFChars(env, string, 0); char cap[128]; strcpy(cap, str); (*env)->ReleaseStringUTFChars(env, string, 0); return (*env)->NewStringUTF(env, strupr(cap));} JNIEXPORT jint JNICALL JNICALL Java_myJNI_myJNI_intArrayMethod (JNIEnv *env, jobject obj, jintArray array){ int i, sum = 0; jsize len = (*env)->GetArrayLength(env, array); jint *body = (*env)->GetIntArrayElements(env, array, 0); for (i = 0; i < len; ++i) { sum += body[i]; } (*env)->ReleaseIntArrayElements(env, array, body, 0); return sum;}
(*env)->GetStringUTFChars()这个方法, 是用来在Java和C之间转换字符串的, 因为Java本身都使用了双字节的字符, 而C语言本身都是单字节的字符,
所以需要进行转换.
JNIEnv *是每个函数都有的参数, 它包含了很多有用的方法, 使用起来类似Java的反射, 也提供了这样一个编码转换的函数.
GetStringUTFChars()和NewStringUTF(), 第一个是从UTF8转换为C的编码格式, 第二个是根据C的字符串返回一个UTF8字符串.
ReleaseStringUTFChars()是用来释放对象的, 在Java中有虚拟机进行垃圾回收, 但是在C语言中, 这些对象必须手动回收. 否则可能造成内存泄漏.
函数的名字一眼看到就可以猜出功能, jni.h中的大部分函数名都是这样.
之后编译就好了。如果编译不出问题就OK了。
四、运行文件
- 在java中调用c语言——JNI入门
- Java Jni入门(一):Hello Jni(在Java中调用C库函数)
- C语言入门&JNI与地层调用——Day01_1
- C语言入门&JNI与地层调用——Day01_2
- C语言入门&JNI与地层调用——Day02_1
- C语言入门&JNI与地层调用——Day02_2
- 跨操作系统的JNI入门(Java调用C语言)
- 跨操作系统的JNI入门(Java调用C语言)
- Android JNI入门第六篇——C调用Java
- Android JNI入门——C调用Java
- Android JNI入门第七篇——C调用Java
- C语言调用Java JNI
- JNI-->Java调用C语言
- JNI-->C调用Java语言
- java jni 调用C语言
- 使用jni实现在C语言中调用Java的方法
- JNI学习系列——在C/C++中调用JAVA
- 使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库
- 弱鸡的HAOI之旅
- 哈希表
- UVA 1339
- python使用JPype来运行java文件
- STM32--今天下午遇到了两个BUG。记录一下(栈溢出和串口调试)
- 在java中调用c语言——JNI入门
- android自动化:Uiautomator定位元素小利器
- 每日一题 No.31 学习ctype.h的用法
- 使用vue+webpack的多页面架构
- 0和 null
- 史上最全的MySQL基础教程(收藏)
- linuxx初级学习之swap分区练习题
- Markdown插入公式~最佳方案
- RecyclerView添加Item的点击事件