JNI:使用RegisterNatives方法传递和使用Java自定义类
来源:互联网 发布:金伯帆酒店事件 知乎 编辑:程序博客网 时间:2024/05/09 21:59
除了使用传统方法实现JNI外,也可以使用RegisterNatives实现JNI。和传统方法相比,使用RegisterNatives的好处有三点:
1、C++中函数命名自由,不必像javah自动生成的函数声明那样,拘泥特定的命名方式;
2、效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数;
3、运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。
为了使用RegisterNatives,我们需要了解JNI_OnLoad和JNI_OnUnload函数。JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用:
C++的代码可以分为两部分:实现callCustomClass方法和注册callCustomClass。
实现callCustomClass方法的代码如下:
C++函数内忽略this指针,他所接收的jobject是“Java程序代码传递过来的Java object reference“在原生端的形式,在C++中对jobject的改变在java中也是有效的。如果想要访问Java数据成员和函数,得先使用GetFieldID或GetMethodID分别获取数据成员和函数的识别码,这两个函数的参数依次为1)class object;2)包含元素名称的字符串;3)表示类型的字符串。
注册callCustomClass在JNI_OnLoad中进行,代码如下:
在C++和Java中创建关联的是JNINativeMethod,它在jni.h中定义:name是java中定义的native函数的名字,fnPtr是函数指针,也就是C++中java native函数的实现。signature是java native函数的签名,可以认为是参数和返回值。比如(LMyJavaClass;)V,表示函数的参数是LMyJavaClass,返回值是void。对于基本类型,对应关系如下:
如果参数是Java类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,例如Ljava/lang/String;,而其对应的C++函数的参数为jobject,一个例外是String类,它对应C++类型jstring。
1、C++中函数命名自由,不必像javah自动生成的函数声明那样,拘泥特定的命名方式;
2、效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数;
3、运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。
为了使用RegisterNatives,我们需要了解JNI_OnLoad和JNI_OnUnload函数。JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用:
- 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
- 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当,RegisterNatives也在这里进行。
JNI_OnUnload()当VM释放该组件时被调用,JNI_OnUnload()函数的作用与JNI_OnLoad()对应,因此在该方法中进行善后清理,资源释放的动作最为合适。
Java代码和使用哪种方式实现JNI无关,如下所示:
- class MyJavaClass
- {
- public int iValue;
- public void Squa(){iValue = iValue*iValue;}
- }
- public class RegisterNativesTest
- {
- static{
- System.load("/home/zmh/workspace/RegisterNativesTest/lib/libCallClass.so");
- }
- public static void main(String[] args)
- {
- RegisterNativesTest app = new RegisterNativesTest();
- MyJavaClass obj = new MyJavaClass();
- obj.iValue = 10;
- System.out.println("Before callCustomClass: " + obj.iValue);
- app.callCustomClass(obj);
- System.out.println("After callCustomClass: " + obj.iValue);
- }
- private native void callCustomClass(MyJavaClass obj);
- }
C++的代码可以分为两部分:实现callCustomClass方法和注册callCustomClass。
实现callCustomClass方法的代码如下:
- void callCustomClass(JNIEnv* env, jobject, jobject obj)
- {
- jclass cls = env->GetObjectClass(obj);
- jfieldID fid = env->GetFieldID(cls, "iValue", "I");
- jmethodID mid = env->GetMethodID(cls, "Squa", "()V");
- int value = env->GetIntField(obj, fid);
- printf("Native: %d\n", value);
- env->SetIntField(obj, fid, 5);
- env->CallVoidMethod(obj, mid);
- value = env->GetIntField(obj, fid);
- printf("Native:%d\n", value);
- }
C++函数内忽略this指针,他所接收的jobject是“Java程序代码传递过来的Java object reference“在原生端的形式,在C++中对jobject的改变在java中也是有效的。如果想要访问Java数据成员和函数,得先使用GetFieldID或GetMethodID分别获取数据成员和函数的识别码,这两个函数的参数依次为1)class object;2)包含元素名称的字符串;3)表示类型的字符串。
注册callCustomClass在JNI_OnLoad中进行,代码如下:
- static JNINativeMethod s_methods[] = {
- {"callCustomClass", "(LMyJavaClass;)V", (void*)callCustomClass},
- };
- int JNI_OnLoad(JavaVM* vm, void* reserved)
- {
- JNIEnv* env = NULL;
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
- {
- return JNI_ERR;
- }
- jclass cls = env->FindClass("LRegisterNativesTest;");
- if (cls == NULL)
- {
- return JNI_ERR;
- }
- int len = sizeof(s_methods) / sizeof(s_methods[0]);
- if (env->RegisterNatives(cls, s_methods, len) < 0)
- {
- return JNI_ERR;
- }
- return JNI_VERSION_1_4;
- }
在C++和Java中创建关联的是JNINativeMethod,它在jni.h中定义:
- /*
- * used in RegisterNatives to describe native method name, signature,
- * and function pointer.
- */
- typedef struct {
- char *name;
- char *signature;
- void *fnPtr;
- } JNINativeMethod;
<p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px;"><span class="pun">字符</span><span class="pln"> </span><span class="typ">Java</span><span class="pun">类型</span><span class="pln"> C</span><span class="pun">/</span><span class="pln">C</span><span class="pun">++类型</span><span class="pln">V </span><span class="kwd">void</span><span class="pln"> </span><span class="kwd">void</span><span class="pln">Z jboolean </span><span class="kwd">boolean</span><span class="pln">I jint </span><span class="kwd">int</span><span class="pln">J jlong </span><span class="kwd">long</span><span class="pln">D jdouble </span><span class="kwd">double</span><span class="pln">F jfloat </span><span class="kwd">float</span><span class="pln">B jbyte </span><span class="kwd">byte</span><span class="pln">C jchar </span><span class="kwd">char</span><span class="pln">S jshort </span><span class="kwd">short</span></p>数组则以"["开始,用两个字符表示,比如int数组表示为[I,以此类推。
如果参数是Java类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,例如Ljava/lang/String;,而其对应的C++函数的参数为jobject,一个例外是String类,它对应C++类型jstring。
0 0
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- 实现JNI的另一种方法:使用RegisterNatives方法传递和使用Java自定义类 (转)
- android开发--- jni使用RegisterNatives注册本地方法
- java JNI 实现原理 (三) JNI中的RegisterNatives方法
- JAVA源码分析之---Object类(一)---registerNatives,getClass方法的使用
- JNI方法的静态注册和动态注册RegisterNatives
- android-jni RegisterNatives注册本地方法
- 使用RegisterNatives注册原生代码
- JNI_OnLoad方法和RegisterNatives方法的结合
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- 足球
- 点号「.」在JavaScript中的语义
- FLAG_ACTIVITY_CLEAR_TOP、FLAG_ACTIVITY_SINGLE_TOP区别
- 找出一个断开的电阻的硬件调试问题思维过程
- uva 414 uva 458 uva 494(水题两三道)
- JNI:使用RegisterNatives方法传递和使用Java自定义类
- 当jsp页面完全加载完成后执行一个js函数
- ViewPager结合Activity的使用及父Activity中调用子Activity的方法
- C#学习笔记
- document.onclick 无效
- Javascript中的线程以及获取动态Dom元素的问题
- 网页上的摄影展:等高响应布局实现
- eclipse maven plugin 插件 安装 和 配置
- 静态代码检查之checkstyle