JNI 方法注册与签名
来源:互联网 发布:js contains方法 编辑:程序博客网 时间:2024/05/20 03:41
最近了解了关于Java JNI接口的一些关于方法注册与签名相关的知识,在此进行一下总结。
使用JNI接口时,我们首先需要把Java方法声明为native:
public native void f();
然后编写对应的C/C++代码,并编译成为动态链接库(.dll或.so),在调用Java方法前载入动态链接库即可调用:
static { System.loadLibrary("native-lib"); }
那么,Java文件中的native方法是如何与native文件中的方法一一对应的呢?
在此有两种方法:静态注册与动态注册,下面将一一介绍:
静态注册
采用静态注册时,Java层的native方法与native层的方法在名称上具有一一对应的关系,具体要求如下:
native层的方法名为:Java_<包名>_<类名>_<方法名>(__<参数>)
其中,包名使用下划线代替点号进行分割
只有当native方法出现需要重载的时候,native层的方法名后才需要跟上参数(括号里的内容),参数的编写形式与JNI签名相关(后面会介绍)
通常而言,我们可以把native方法集中在一个类中,然后调用:
javah -jni 包名.类名
自动生成对应的c层头文件
下面是静态注册的例子:
Java层:
package com.app.superxlcr.jnitest;/** * Created by superxlcr on 2017/5/25. */public class NativeTest { public native void f(); public native int f(int a, double b); public native void f(Object a, String b); public native void g();}
native层:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_app_superxlcr_jnitest_NativeTest */#ifndef _Included_com_app_superxlcr_jnitest_NativeTest#define _Included_com_app_superxlcr_jnitest_NativeTest#ifdef __cplusplusextern "C" {#endif/* * Class: com_app_superxlcr_jnitest_NativeTest * Method: f * Signature: ()V */JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__ (JNIEnv *, jobject);/* * Class: com_app_superxlcr_jnitest_NativeTest * Method: f * Signature: (ID)I */JNIEXPORT jint JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__ID (JNIEnv *, jobject, jint, jdouble);/* * Class: com_app_superxlcr_jnitest_NativeTest * Method: f * Signature: (Ljava/lang/Object;Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__Ljava_lang_Object_2Ljava_lang_String_2 (JNIEnv *, jobject, jobject, jstring);/* * Class: com_app_superxlcr_jnitest_NativeTest * Method: g * Signature: ()V */JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_g (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
我们可以看到,对于拥有重载的f 方法,其native方法名称后都带有参数,而没有重载的g 方法则没带有
静态注册JNI方法的弊端非常明显,就是方法名会变得很长,因此下面我们介绍另外一种动态注册的方法
动态注册
使用动态注册时,我们需要准备好需要自己想要对应的native方法,然后构造JNINativeMethod数组,JNINativeMethod是一种结构体,源码如下:
typedef struct {// Java层native方法名称 const char* name;// 方法签名 const char* signature;// native层方法指针 void* fnPtr;} JNINativeMethod;
然后重写JNI_OnLoad方法(该方法会在Java层通过System.loadLibrary加载完动态链接库后被调用),我们在其中进行动态注册工作:
JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env = NULL; jint result = -1; // 获取JNI env变量 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { // 失败返回-1 return result; } // 获取native方法所在类 const char* className = "com/app/superxlcr/jnitest/MainActivity"; jclass clazz = env->FindClass(className); if (clazz == NULL) { return result; } // 动态注册native方法 if (env->RegisterNatives(clazz, methods, 1) < 0) { return result; } // 返回成功 result = JNI_VERSION_1_4; return result;}
动态注册的大致步骤如下:
- 通过vm(Java虚拟机)参数获取JNIEnv变量
- 通过FindClass方法找到对应的Java类
- 通过RegisterNatives方法,传入JNINativeMethod数组,注册native函数
对于JNINativeMethod结构而言,签名是其非常重要的一项元素,它用于区分Java中native方法的各种重载形式,下面将介绍方法的签名
方法签名
方法签名对于区分Java层native重载方法有重大意义
总的来说,方法签名的组成规则为:
(参数类型标识1参数类型标识2...参数类型标识n)返回值类型标识
类型标识Java类型ZbooleanBbyteCcharSshortIintJlongFfloatDdoubleL包名/类名;各种引用类型Vvoid
另外,当Java类型为数组时,在标识前会有“[”符号,例如:String[] 类型标识为 [Ljava/lang/String;
下面举几个例子:
// Signature: ()Vpublic native void f();// Signature: (ID)Ipublic native int f(int a, double b);// Signature: (Ljava/lang/Object;Ljava/lang/String;)Vpublic native void f(Object a, String b);// Signature: ()Vpublic native void g();
阅读全文
0 0
- JNI 方法注册与签名
- Java方法签名与JNI,反射
- JNI方法签名规则
- JNI方法签名规则
- JNI中方法签名
- JNI方法签名规则
- JNI方法签名规则
- jni 注册方法
- JNI注册函数方法
- JNI动态注册方法
- JNI类型签名和方法签名
- JNI之GetMethodID方法签名
- JNI签名与数据匹配
- JNI Java 类签名 方法签名 参数签名
- jni方法动态注册--C++
- 浅谈动态注册JNI方法
- JNI函数的注册方法
- JNI里的数据类型 和签名方法
- 蓝牙状态
- 将博客搬至博客园http://www.cnblogs.com/daxianghaoshuai/
- pat1002.写出这个数(20)
- Linux-vi/vim常用命令手册
- 122. Best Time to Buy and Sell Stock II
- JNI 方法注册与签名
- Windows下如何使用curl命令?
- Android内存优化
- Maven 手动添加 JAR 包到本地仓库
- java JAI 实现多页TIF文件拆分保存成PNG格式
- PLSQL安装配置与错误解决
- C++中将图片序列写出到硬盘上?
- gcc升级
- axis的对象序列化中的复杂对象处理