文章目录
1.java方法与原生实例方法参数的关系。
java实例方法对应jobject,java静态方法对应jclass。
public static native String stringFromJNI();
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_testndk_JniUtil_stringFromJNI(JNIEnv *env, jclass thiz){}
public native String stringFromJNI();
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_testndk_JniUtil_stringFromJNI(JNIEnv *env, jobject thiz) {}
2.java与c/c++的基本数据类型关系
3.java应用类型与原生的关系
4.字符串的相关操作
把java字符串转换成C字符串
//JNI_TRUE 返回的字符串地址指向副本
//JNI_FALSE 回的字符串地址指向堆中的固定对象
jboolean bo = JNI_FALSE;
//创建字符串
jstring ss = env->NewStringUTF("hello world");
//将jstring转换成可操作性的字符串
const char *str = env->GetStringUTFChars(ss, &bo);
if (str != 0) {
printf("111111111111111%s", str);
}
释放字符串(不像java有垃圾回收器,申请就需要释放)
env->ReleaseStringUTFChars(ss,str);
5.数组操作
(1)创建数组
New<Type>Array
Type:对应Int、Char、Bollean等
使用实例:
jintArray array = env->NewIntArray(10);
(2)访问数组(副本)
//转换数组
jint nativeARRAY[5];
env->GetIntArrayRegion(array, 0, 5, nativeARRAY);
//操作数组,从C数组向java数组提交所做的修改
nativeARRAY[0] = 100;
env->SetIntArrayRegion(array, 0, 5, nativeARRAY);
java
int[] array = {10, 11, 12, 13, 14};
arrayOperation(array);
for (int i = 0; i < 5; i++) {
Log.i("mainActivity", array[i] + "");
}
输出结果
2020-03-14 17:35:12.173 18150-18150/com.example.testndk I/mainActivity: 100
2020-03-14 17:35:12.173 18150-18150/com.example.testndk I/mainActivity: 11
2020-03-14 17:35:12.173 18150-18150/com.example.testndk I/mainActivity: 12
2020-03-14 17:35:12.173 18150-18150/com.example.testndk I/mainActivity: 13
2020-03-14 17:35:12.175 18150-18150/com.example.testndk I/mainActivity: 14
(3)访问数组(对直接指针的操作)
//获取直接指针
jint *myInt = env->GetIntArrayElements(array, JNI_FALSE);
//操作数组,提交修改并释放内存
myInt[0] = 1555;
env->ReleaseIntArrayElements(array, myInt, 0);
java
int[] array = {10, 11, 12, 13, 14};
arrayOperation(array);
for (int i = 0; i < 5; i++) {
Log.i("mainActivity", array[i] + "");
}
输出结果
2020-03-14 20:45:50.064 19088-19088/com.example.testndk I/mainActivity: 1555
2020-03-14 20:45:50.065 19088-19088/com.example.testndk I/mainActivity: 11
2020-03-14 20:45:50.065 19088-19088/com.example.testndk I/mainActivity: 12
2020-03-14 20:45:50.065 19088-19088/com.example.testndk I/mainActivity: 13
2020-03-14 20:45:50.065 19088-19088/com.example.testndk I/mainActivity: 14
ReleaseIntArrayElements第三个参数mode说明。
6.NIO操作
//创建直接字节缓冲区
unsigned char *buffer = (unsigned char *) malloc(1024);
jobject objBuffer = env->NewDirectByteBuffer(buffer, 1024);
//获取缓冲区
unsigned char *buffer2 = (unsigned char *)env->GetDirectBufferAddress(objBuffer);
7.访问域
extern "C" JNIEXPORT void JNICALL
Java_com_example_testndk_MainActivity_fieldOperation(
JNIEnv *env,
jobject /* this */, jobject obj) {
//实例域
//获取域id,Ljava/lang/String;
jclass cls = env->GetObjectClass(obj);
jfieldID fId = env->GetFieldID(cls, "size", "Ljava/lang/String;");
//获取域
jstring str = (jstring) env->GetObjectField(obj, fId);
const char *c = env->GetStringUTFChars(str, JNI_FALSE);
LOGI("%s", c);
//静态域
//获取域id
jfieldID fId2 = env->GetStaticFieldID(cls, "staticSize", "Ljava/lang/String;");
//获取域
jstring str2 = (jstring) env->GetStaticObjectField(cls, fId2);
const char *c2 = env->GetStringUTFChars(str2, JNI_FALSE);
LOGI("%s", c2);
}
java
public class MyBox {
private String size = "instance";
private static String staticSize = "static";
}
MyBox myBox = new MyBox();
fieldOperation(myBox);
输出结果
2020-03-14 23:53:00.647 21624-21624/com.example.testndk I/test-jni: instance
2020-03-14 23:53:00.647 21624-21624/com.example.testndk I/test-jni: static
8.调用方法
extern "C" JNIEXPORT void JNICALL
Java_com_example_testndk_MainActivity_methodOperation(
JNIEnv *env,
jobject /* this */, jobject obj) {
//获取class
jclass cls = env->GetObjectClass(obj);
//获取实例方法id
jmethodID mId = env->GetMethodID(cls, "instanceMethod", "()Ljava/lang/String;");
//调用实例方法
jstring result = (jstring) env->CallObjectMethod(obj, mId);
const char *c = env->GetStringUTFChars(result, JNI_FALSE);
LOGI("%s",c);
//获取静态方法id
jmethodID mId2 = env->GetStaticMethodID(cls, "staticMethod", "()Ljava/lang/String;");
//调用静态方法
jstring result2 = (jstring) env->CallStaticObjectMethod(cls, mId2);
const char *c2 = env->GetStringUTFChars(result2, JNI_FALSE);
LOGI("%s",c2);
}
java
public class MyBox {
private String instanceMethod() {
return "instance";
}
private static String staticMethod() {
return "static";
}
}
MyBox myBox = new MyBox();
methodOperation(myBox);
输出内容
2020-03-15 13:50:54.937 21991-21991/com.example.testndk I/test-jni: instance
2020-03-15 13:50:54.937 21991-21991/com.example.testndk I/test-jni: static
9.域和方法的描述符
这类数据是描述符
()Ljava/lang/String;
Ljava/lang/String;
android studio的描述符配置,使得获取描述符更简单。
file→setting→tools→external tools
点击+号,name随意,其他如下:
program:$JDKPath$/bin/javap
arguments:-s -p $FileClass$
working directory:$ModuleFileDir$\build\intermediates\javac\debug\classes
点击ok,完成。
使用:点击菜单tools→external tools→你起的名字
效果:
D:\Android_develop\android_studio\jre/bin/javap -s -p com.example.testndk.MyBox
Compiled from "MyBox.java"
public class com.example.testndk.MyBox {
public com.example.testndk.MyBox();
descriptor: ()V
private java.lang.String instanceMethod();
descriptor: ()Ljava/lang/String;
private static java.lang.String staticMethod();
descriptor: ()Ljava/lang/String;
}
Process finished with exit code 0
10.在原生代码中使用log
#include <android/log.h>
#define LOG "test-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__) // 定义LOGF类型
使用
LOGI("%s",c);