有时候,我们需要在Java代码中调用c/c++代码,大致的格式是这样的:
public native void helloworld();
但是但是如何让这个java方法和c/c++中的方法对应起来呢,也既是当我们在java中调用被声明为native
的方法时,自动调用c/++中的方法.这种对应关系,有两种方式来实现:静态注册和动态注册.下面我们来了解一下:
静态注册
所谓静态注册,通常步骤大致如下:
1. 编写需要的Java方法,并编译出class文件:
public class StaticRegisterNativeMethod {
static {
System.loadLibrary("RegisterMethodTest");
}
public native String hello();
}
2. 通过javah
工具生成对应的.h
头文件:
javah -o xxx.h packagename.DynamicRegisterNativeMethod
头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_xiao_jnitest_StaticRegisterNativeMethod */
#ifndef _Included_com_xiao_jnitest_StaticRegisterNativeMethod
#define _Included_com_xiao_jnitest_StaticRegisterNativeMethod
#ifdef __cplusplus
extern "C" {
#endif
/* * Class: com_xiao_jnitest_StaticRegisterNativeMethod * Method: hello * Signature: ()Ljava/lang/String; */
JNIEXPORT jstring JNICALL Java_com_xiao_jnitest_StaticRegisterNativeMethod_hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3. 在.c
文件中编写我们的实现:
#include <string.h>
#include "StaticRegisterMethod.h"
/* * Class: com_xiao_jnitest_StaticRegisterNativeMethod * Method: hello * Signature: ()Ljava/lang/String; */
jstring Java_com_xiao_jnitest_StaticRegisterNativeMethod_hello
(JNIEnv *env, jobject instance){
return (*env)->NewStringUTF(env, "World from static register method!");
}
4. 之后,我们在Java文件中使用hello
这个方法时,jvm会自动帮我们和c/c++中方法对应起来:
总结:
然后我们就发现,写个native方法好麻烦啊,而且c/c++中对应的方法名十分不人性化,弊端大致有:
- 声明native的java类,每个对应的class文件都要用javah命令生成头文件,好烦人.而且,以后修改了java中方法的定义,又要重新生成头文件.
- javah生成的native函数名特别长,对人不友好
- 初次调用native方法时,jvm要根据函数名字搜索对应的native方法建立关联关系,影响运行效率.
于是就出现了下面这种动态注册方案
动态注册
步骤如下:
1. 编写需要的Java方法:
public class DynamicRegisterNativeMethod {
static {
System.loadLibrary("RegisterMethodTest");
}
public native String hello();
}
2. 在对应的c/c++文件中,编写native实现:
jstring DynamicRegisterNativeMethod_hello
(JNIEnv *env, jobject instance)
{
return (*env)->NewStringUTF(env, "World from dynamic register method!");
}
3. 通过JNINativeMethod
来构建一个数组,声明java方法和native方法的对应关系:
static JNINativeMethod gMethods[] =
{
{
"hello", //Java中native函数的函数名
"()Ljava/lang/String;", // Java中的native对应的native签名
(void *)DynamicRegisterNativeMethod_hello //native 中的方法指针
},
};
4. 在我们调用System.loadLibrary()
方法时,native中的JNI_OnLoad
方法会被调用,因此我们需要在这个方法中动态注册我们的jni方法:
int register_method(JNIEnv *env)
{
jclass clazz = (*env)->FindClass(env, "com/xiao/jnitest/DynamicRegisterNativeMethod");
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env=NULL;
jint result = -1;
if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK){
return -1;
}
assert(env != NULL);
if(!register_method(env)){
return -1;
}
result = JNI_VERSION_1_4;
return result;
}
5. 最后,我们在Java文件中使用hello
这个方法,结果就像下面这样:
结语
动态注册和静态注册大致就是这样.上面我们提到,静态注册在初次使用native方法时,需要建立native方法和java方法之间的关联,因此会必将耗时,那么我们来测试一下静态加载的状况:
MainActivity: Static register method cost time:14 //第一次
MainActivity: Static register method cost time:3
MainActivity: Static register method cost time:4
MainActivity: Static register method cost time:11 //第一次
MainActivity: Static register method cost time:3
MainActivity: Static register method cost time:3
MainActivity: Static register method cost time:11 //第一次
MainActivity: Static register method cost time:5
MainActivity: Static register method cost time:4
我们发现,第一次的确比较耗时,那么对比一下动态加载:
MainActivity: Dynamic register method cost time:11 //第一次
MainActivity: Dynamic register method cost time:3
MainActivity: Dynamic register method cost time:3
MainActivity: Dynamic register method cost time:11 //第一次
MainActivity: Dynamic register method cost time:5
MainActivity: Dynamic register method cost time:5
MainActivity: Dynamic register method cost time:10 //第一次
MainActivity: Dynamic register method cost time:3
MainActivity: Dynamic register method cost time:4
然后我们发现,第一次使用时的时间差异并不明显.不过这有一部分原因是我们的native方法笔记少,当方法数量增多时,需要重新测试才能知道结果了.
今天的文章Android JNI初步☞Java方法和native方法关联分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/29630.html