速学JNI(Java 代码调用 C 函数)
整个Demo下载
链接:https://github.com/linweimao/NDK-Java-C-
建议先看上篇文章
生成头文件的方式
点击 Terminal 输入命令,便可以生成一个JNI的 C 头文件.
输入第二个命令行提示错误的原因是注释为中文。所以在输入命令行时不能出现注释或者中文
javac -h ./ JNI.java
上面的命令的作用:根据Java中的 native 方法生成对应在 C 中的方法该怎么写(自动生成)
这样为正确的,输入命令行没问题
这样会提示错误
下图为生成的头文件
JNI的头文件的代码如下
Java 调用 C 函数执行加法运算
测试1: 将传入的两个int值相加并返回
- 测试目标: int值运算
- Java端代码
public native int sum(int x, int y); - C端代码
JNIEXPORT jint JNICALL Java_com_atguigu_javacallc_JNIS_sum
(JNIEnv * env, jobject obj, jint x, jint y) {
//jint可以直接进行算术运算
int sum = x+y;
printf("printf c sum=%d\n", sum);//问题: 直接输出在eclipse的logcat中看不到输出
//可直接将int类型数据作为jint返回
return sum;
}
Java 调用 C 函数执行字符串运算
测试2: 将两个字符串拼接后返回
-
测试目标: 字符串操作
-
Java端代码
public native String sayHello(String s);
- C端代码(用到的函数 strcat )
/**
* 工具函数
* 把一个jstring转换成一个c语言的char* 类型.
*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}
/**
* 字符串操作: 将两个字符串拼接后返回
//1. 将jstring类型的js转换为char*类型数据
//2. 指定另一部分字符串
//3. 将拼接两个char*类型字符串拼接在第一个上
//string.h---char* strcat(char *, const char *);
//4. 将结果转换为jstring类型返回
//jstring (*NewStringUTF)(JNIEnv*, const char*)
*/
JNIEXPORT jstring JNICALL Java_com_atguigu_javacallc_JNIS_sayHello
(JNIEnv * env, jobject obj, jstring js) {
//1. 将jstring类型的js转换为char*类型数据
char* cs1 = _JString2CStr(env, js);
//2. 指定另一部分字符串
char* cs2 = " Hello By C";
//3. 将拼接两个char*类型字符串拼接在第一个上
char* cs3 = strcat(cs1, cs2);
//4. 将结果转换为jstring类型返回
return (*env)->NewStringUTF(env, cs3);
}
Java 调用 C 函数执行数组运算
测试3:将数组中的每个元素增加10
- 测试目标: 数组运算
- Java端代码
public native int[] increaseArrayEles(int[] intArray);
- C端代码
/**
* 数组运算: 将数组中的每个元素增加10
//1. 得到数组的长度
//jsize (*GetArrayLength)(JNIEnv*, jarray);
//2. 得到数组
//jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
//3. 遍历数组, 并将每个元素+10
//4. 返回数组
*/
JNIEXPORT jintArray JNICALL Java_com_atguigu_javacallc_JNIS_increaseArrayEles
(JNIEnv * env, jobject obj, jintArray arr) {
//1. 得到数组的长度
//jsize (*GetArrayLength)(JNIEnv*, jarray);
jsize length = (*env)->GetArrayLength(env, arr);
//2. 得到数组
//jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
jint* array = (*env)->GetIntArrayElements(env, arr, JNI_FALSE);
//3. 遍历数组, 并将每个元素+10
int i;
for(i=0;i<length;i++) {
*(array+i) += 10;
}
//4. 返回数组
return arr;
}
检查密码是否正确
小应用: 检查密码是否正确, 如果正确返回200, 否则返回400
- Java端代码
/*
* 应用: 检查密码是否正确, 如果正确返回200, 否则返回400
"123456"
*/
public native int checkPwd(String pwd);
- C端代码(用到的函数 strcmp)
/**
* 小应用: 检查密码是否正确
//1. 将jString转换为char*
//2. 比较两个字符串是否相等
//string.h---int strcmp(const char *, const char *)
//3. 根据比较的结果返回不同的值
*/
JNIEXPORT jint JNICALL Java_com_atguigu_javacallc_JNIS_checkPwd
(JNIEnv * env, jobject obj, jstring js) {
//1. 将jString转换为char*
char* cs = _JString2CStr(env, js);
char* pwd = "123456";
//2. 比较两个字符串是否相等
int result = strcmp(cs, pwd);
//3. 根据比较的结果返回不同的值
if(result==0) {
return 200;
}
return 400;
}