[TOC]

概述

数据类型

JNI的基础数据类型转换

1
2
3
4
5
6
7
8
9
10
// JNI的数据类型和C++中的数据类型的对照表
/* Primitive types that match up with Java equivalents. */
//typedef uint8_t jboolean; /* unsigned 8 bits */
//typedef int8_t jbyte; /* signed 8 bits */
//typedef uint16_t jchar; /* unsigned 16 bits */
//typedef int16_t jshort; /* signed 16 bits */
//typedef int32_t jint; /* signed 32 bits */
//typedef int64_t jlong; /* signed 64 bits */
//typedef float jfloat; /* 32-bit IEEE 754 */
//typedef double jdouble; /* 64-bit IEEE 754 */

我们声明一个JNI调用JNI的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class JniBasicType {

static {
System.loadLibrary("hello-jni");
}

public static native int callNativeInt(int num);

public static native byte callNativeByte(byte b);

public static native char callNativeChar(char ch);

public static native short callNativeShort(short sh);

public static native long callNativeLong(long l);

public static native float callNativeFloat(float f);

public static native double callNativeDouble(double d);

public static native boolean callNativeBoolean(boolean value);
}

修改cmakelist文件

1
2
3
4
5
6
7
8
9
# 添加源文件或者库.根据C++文件,我们要把hello-jni.cpp编译成一个hello-jni的SO
add_library( # Sets the name of the library.
hello-jni # 库的名字
# Sets the library as a shared library.
SHARED #库的类型 共享库(动态)库、如果是STATIC的话,就是静态库
# Provides a relative path to your source file(s).
hello-jni.cpp
jni/jni_basic_type.cpp
) # 库的源文件

我们新建了一个jni/jni_basic_type.cpp的文件,但是他依然是hello-jni这个库里面的Native方法

image-20210130185734185

下面是具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//===============================学习Jni的基础数据类型========================
/**
* 第一个参数:是JNI的ENV环境
* 第二个参数:因为我们这些方法在Jave那边都是静态方法,所以我们这个参数类型是jclass
* 如果是实例方法的话,我们使用的是jobject
* 后面的参数就是方法是实际参数
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeInt(JNIEnv *env, jclass thiz, jint num) {
LOG_D("JAVA int value is %d", num);
int c_num = num * 2;
return c_num;
}

extern "C"
JNIEXPORT jbyte JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeByte(JNIEnv *env, jclass thiz, jbyte b) {
LOG_D("java byte value is %d", b);
jbyte c_byte = b + (jbyte) 10;
return c_byte;
}

extern "C"
JNIEXPORT jchar JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeChar(JNIEnv *env, jclass thiz, jchar ch) {

LOG_D("java char value is %c", ch);
jchar c_char = ch + (jchar) 3;
return c_char;
}

extern "C"
JNIEXPORT jshort JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeShort(JNIEnv *env, jclass thiz, jshort sh) {
LOG_D("java char value is %d", sh);
jshort c_short = sh + (jshort) 10;
return c_short;
}

extern "C"
JNIEXPORT jlong JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeLong(JNIEnv *env, jclass thiz, jlong l) {
LOG_D("java long value is %ld", l);
jlong c_long = l + 100;
return c_long;
}

extern "C"
JNIEXPORT jfloat JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeFloat(JNIEnv *env, jclass thiz, jfloat f) {
LOG_D("java float value is %f", f);
jfloat c_float = f + (jfloat) 10.0;
return c_float;
}

extern "C"
JNIEXPORT jdouble JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeDouble(JNIEnv *env, jclass thiz, jdouble d) {
LOG_D("java double value is %f", d);
jdouble c_double = d + 20.0;
return c_double;
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeBoolean(JNIEnv *env, jclass thiz, jboolean value) {
LOG_D("java boolean value is %d", value);
jboolean c_bool = (jboolean) !value;
return c_bool;
}

JNI的字符串数据类型转换

image-20210130190451762

​ String就不能像基础数据类型一样直接进行转换了。我们需要通过

​ 因为Java一般都是UTF编码的,所以我们只需要调用

1
env->GetStringUTFChars(string)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* JNI层和Java层的字符串之间的转换
*/
extern "C"
JNIEXPORT jstring JNICALL
Java_com_frewen_android_demo_logic_samples_jni_JniBasicType_callNativeString(JNIEnv *env, jclass clazz, jstring jString) {
// 定义一个char*的数组的常量.为C中的str字符串分配内存空间
const char *str = env->GetStringUTFChars(jString, 0);
LOG_D("传入的Java的String是:%s", str);

/// 计算传入的字符串的长度
int len = env->GetStringUTFLength(jString);
LOG_D("传入的Java的String的长度是:%d", len);

/// 计算传入的字符串的0-len - 10的字符串存储到Buff中
char buff[128];
env->GetStringUTFRegion(jString, 0, len - 10, buff);
LOG_D("传入的Java的String的Buffer:%s", buff);

// 用完之后,进行删除,避免出现内存泄露的问题。
// 上面GetStringUTFChars和ReleaseStringUTFChars这两个函数是配套使用的
env->ReleaseStringUTFChars(jString, str);
// 因为Java都是Unicode编码,所以我们返回的也是NewStringUTF
return env->NewStringUTF("这是C环境的字符串 %s");

}

JNI中引用类型的转换