调用jni的两种方法javah和RegisterNatives
2018-02-05 11:35
393 查看
前言:
调用jni的有两种方法:一种是通过javah 自动生成jni文件
一种是加载类库的时候,调用JNIEnv 指针的RegisterNatives方法注册native方法
RegisterNatives方式有3种好处
1、jni种函数命名自由,不必像javah自动生成的函数声明那样,必须特定的命名方式;
2、效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数;
3、运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。
一、javah生成jni
java类中声明 native 方法public native String stringFromJNI();
通过javah方法生成jni文件。(cmd命令进入包根目录,javah 包名.类名)
生成方法会带JNIEXPORT void JNICALL 方法名很长,包名和native方法结合在一起。如:
//返回类型 JNIEXPORT jstring JNICALL //生成的方法名字 Java_libyuv_aimissu_com_libyuvtestdemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
二、RegisterNatives 注册native方法
1. java类中声明 native 方法public native String stringFromJNI();
2. 定义JNINativeMethod集合,对应java类中native方法
/** * native方法集合 */ static JNINativeMethod mynative_methods[] = { //java类中声明的native方法名字 (参数,参数。。。)返回值类型 jni中对应的方法 {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI}, {"getTestMethod", "(Ljava/lang/String;IJD)I", (void *) getTestMethod} };
关键是JNINativeMethod集合不要写错,参数和返回值都要和java类中声明的对应上
一个JNINativeMethod对应一个native方法
JNINativeMethod 的结构体 typedef struct { //java类中声明的native方法名字 const char* name; //方法签名(参数类型,参数类型。。。)返回值类型 const char* signature; jni中对应的方法 void* fnPtr; } JNINativeMethod;
属性signature签名
()表示没有参数,
(I)表示一个整形参数,
(I)I 表示一个整形参数返回值是整形,
(Ljava/lang/String;D[I)J 表示有三个参数一个字符串,一个double类型,一个int []数组,J表示long返回值
对应于Java的数据类型,对应native 类型,对应签名
java类型 | native 类型 | 类型签名 |
---|---|---|
boolean | jboolean | Z |
byte | jbyte | B |
char | jchar | C |
short | jshort | S |
int | jint | I |
long | jlong | J |
float | jfloat | F |
double | jdouble | D |
类 | L全限定类名 | |
数组 | [元素组类型签名 |
public native int getTestMethod2(String str,int length,long b,double[] c);
上面这个方法对应的签名是: (Ljava/lang/String;IJD)I
3. RegisterNatives注册JNINativeMethod集合
3.1 jni中覆写JNI_OnLoad(JavaVM *vm, void *reserved) 方法,java类中加载类库System.loadLibrary(“”)的时候回执行这个方法
3.2 RegisterNatives注册JNINativeMethod集合
在JNI_OnLoad中获取JNIEnv 指针,通过JNIEnv 调用RegisterNatives注册native方法
完整代码如下:
#include <jni.h>
#include <string>
#include <android/log.h>
#define LIBENC_LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "mynative", __VA_ARGS__))
#define LIBENC_ARRAY_ELEMS(a) (sizeof(a) / sizeof(a[0]))
static JavaVM *jvm;
static JNIEnv *jenv;
//native测试方法
static jstring stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
//native测试方法
jint getTestMethod(
JNIEnv *env,
jobject,jstring str,jint a,jlong b,jdouble c) {
return 123456;
}
/** * native方法集合 */ static JNINativeMethod mynative_methods[] = { //java类中声明的native方法名字 (参数,参数。。。)返回值类型 jni中对应的方法 {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI}, {"getTestMethod", "(Ljava/lang/String;IJD)I", (void *) getTestMethod} };
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jvm = vm;
//获取JNIEnv 指针
if (jvm->GetEnv((void **) &jenv, JNI_VERSION_1_6) != JNI_OK) {
LIBENC_LOGE("Env not got");
return JNI_ERR;
}
//类似反射得到声明native方法的路径包名+类名
jclass clz = jenv->FindClass("libyuv/aimissu/com/libyuvtestdemo/MainActivity");
if (clz == NULL) {
LIBENC_LOGE("Class \"libyuv/aimissu/com/libyuvtestdemo/MainActivity\" not found");
return JNI_ERR;
}
//注册
if (jenv->RegisterNatives(clz, mynative_methods, LIBENC_ARRAY_ELEMS(mynative_methods))) {
LIBENC_LOGE("methods not registered");
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
相关文章推荐
- JAVA用JNI方法调用C代码实现HelloWorld(含windows及ubuntu两种操作系统环境下的操作)
- PHP中调用Java类的两种方法
- 两种php调用Java对象的方法
- JAVA通过JNI调用本地C语言方法
- PHP中调用Java类的两种方法
- 实践Java中,Jni调用DLL文件本地方法
- JAVA通过JNI调用本地C语言方法
- JNI学习笔记3——本地方法取得Java属性/调用java方法
- Java通过JNI调用C语言的方法
- JNI调用Java方法
- java反射中两种方法的不同(反射能否实现对类的私有方法的调用)
- 两种php调用Java对象的方法
- Java通过JNI调用C语言的方法
- JAVA通过JNI调用本地C语言方法
- JAVA通过JNI调用本地C语言方法
- Java调用WebService(axis2)两种方法
- JAVA通过JNI调用本地C语言方法
- 10,JAVA通过JNI调用本地C语言方法
- JAVA通过JNI调用本地C语言方法
- JAVA通过JNI调用本地C语言方法