一.动态注册和静态注册

  注册native方法有两种方式,动态注册和静态注册。静态注册是在编译时进行注册,而且在java中声明的native方法和c/c++中的本地方法的对应关系是恒定的;比如说在com.example.test包下的Test类中声明了一个stringFromJNI()的native方法,那么它对应的c/c++中的本地方法名就是Java_com_example_test_Test_stringFromJNI();并且这个方法名不能做任何的修改,在java中调用stringFromJNI()函数时,就会按包名_类名_方法名的形式找到对应的方法并调用。而动态注册是在运行时进行注册的,而且本地方法的名字可以按自己的喜好随意取,只要说明了java中声明的native方法和c/c++中的本地方法的对应关系即可。下面用代码的形式来演示一下动态注册的使用步骤。

二.动态注册的步骤

  1.在java中声明native方法,并在静态代码块中加载动态库:

public class Test {
static{
System.loadLibrary("dynamic"); //加载动态库
}
  //声明native方法
native String stringFromJNI(); native static int add(int a,int b);
}

  2.注册函数:在java中加载动态库的时候,虚拟机会调用JNI库中的JNI_Onload()函数,动态注册就是在这个函数中进行的。动态注册使用的是RegisterNatives()方法,这个方法接收3个参数,分别是:

    1.jclass clazz  声明native方法的java类

    2.const JNINativeMethod* methods  JNINativeMethod类型的结构体数组,我们就是在这个结构体数组中说明java方法和本地方法的对应关系的

    3.jint nMethods  第二个参数methods所指向的结构体数组的大小

    JNINativeMethod结构体的定义如下:

    typedef struct {
const char* name;//java中的方法名
const char* signature;//jni签名
void* fnPtr;//本地函数的指针
} JNINativeMethod;

    下面给出这部分的代码:

#include <jni.h>
#include <string>
using namespace std; /**
*实现本地方法,名字可以任取,方法的前两个参数是固定的,后面的参数就是实际的参数
*/ jstring native_stringFromJNI(JNIEnv *env,jobject thiz){
return env->NewStringUTF("nihao");
}
jint native_add(JNIEnv *env,jobject thiz,jint a,jint b){
return a+b;
} static const JNINativeMethod nativeMethod[]={
{"stringFromJNI","()Ljava/lang/String;", (void *) native_stringFromJNI},
{"add","(II)I",(void *)native_add}
}; static int registerNativeMethod(JNIEnv *env){
int result=-1;
jclass clazz=env->FindClass("com/example/dynamicregister/Test");
if(env->RegisterNatives(clazz,nativeMethod,sizeof(nativeMethod)/sizeof(nativeMethod[0]))==JNI_OK){
result=0;
}
return result;
} jint JNI_OnLoad(JavaVM *vm,void *reserved){//这个方法是一个override方法,在加载动态库时,会自动调用,一般用来做一些初始化操作,动态注册的代码就可以写在这
JNIEnv *env= nullptr;
if(vm->GetEnv((void **)&env,JNI_VERSION_1_4)==JNI_OK){//首先需要获取JNIEnv *env指针,因为registerNativeMethod方法会用到
if(registerNativeMethod(env)==0){
return JNI_VERSION_1_4; //返回值代表动态库需要的jni版本
}
}
return -1;
}

  3.在java中调用native函数:

public class MainActivity extends AppCompatActivity {
private TextView tv_display; @SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_display=findViewById(R.id.tv_display);
tv_display.setText(Test.add(1,10)+"");
}
}

三.JNI签名

  下面我把和签名有关的代码单独拿出来进行说明:

static const JNINativeMethod nativeMethod[]={
{"stringFromJNI","()Ljava/lang/String;", (void *) native_stringFromJNI},
{"add","(II)I",(void *)native_add}
};

  比如第一个函数的签名:()Ljava/lang/String;其实表示的是java中的stringFromJNI函数的形参为空,返回值类型为String。

  第二个函数的签名(II)I表示java中的add函数的形参列表是(int,int),返回值类型也是int类型。

  那这个签名有什么作用呢?其实是为了解决java中的函数重载问题。比如,如果java中还声明了一个方法,native String stringFromJNI(String str);那么如果没有函数签名的话,就不知道c/c++中的native_stringFromJNI()对应的是java中的哪个stringFromJNI函数。

  接下来,通过一个表格来说明JNI基本类型的签名以及引用类型的签名:

   

  特别需要注意的是,引用类型签名后面的分号;一定不能省略,否则编译通过不了。

    

    

JNI动态注册以及JNI签名的更多相关文章

  1. JNI动态注册native方法及JNI数据使用

    前言 或许你知道了jni的简单调用,其实不算什么百度谷歌一大把,虽然这些jni绝大多数情况下都不会让我们安卓工程师来弄,毕竟还是有点难,但是我们还是得打破砂锅知道为什么这样干吧,至少也让我们知道调用流 ...

  2. Android Studio NDK JNI动态注册本地方法

    概述 可能大家觉得javah生成的函数名又臭又长,不太好看.这里可以提供另外一种方法来动态注册c++函数,让其根Java中的native方法关联起来. 实现 这里通过JNIEnv的Resisterna ...

  3. Android JNI和NDK学习(03)--动态方式实现JNI(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092491.html 前面总结了静态实现JNI的方法,本文介绍如何动态实现J ...

  4. android nativate 动态注册 静态注册

    说明:在java函数的入口比较容易分析, 把activity的生命周期或者关键函数通过放在so层,分析起来就困难多了 1.在MainActivity中 package com.demo.nativat ...

  5. JNI 方法注册与签名+BufferedReader使用readLine问题

    最近了解了关于JavaJNI接口的一些关于方法注册与签名相关的知识,在此进行一下总结. 使用JNI接口时,我们首先需要把Java方法声明为native: public native void f(); ...

  6. Android 动态注册JNI函数

    1.JNI函数注册方式 在Android开发中,由于种种原因我们需要调用C/C++代码,在这个时候我们就需要使用jni了, jni在使用时要对定义的函数进行注册,这样java才能通过native关键字 ...

  7. Android深入理解JNI(一)JNI原理与静态、动态注册

    前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层.这一个系列我们来一起深入学习JNI. ...

  8. JNI原理与静态、动态注册

    前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层.这一个系列我们来一起深入学习JNI. ...

  9. ndk学习20: jni之OnLoad动态注册函数

    一.原理 当在系统中调用System.loadLibrary函数时,该函数会找到对应的动态库, 然后首先试图找到"JNI_OnLoad"函数,如果该函数存在,则调用它 JNI_On ...

  10. JNI静态注册与动态注册详解

    JNI注册,是指将java层方法(native关键字修饰的)和C层方法对应起来,以实现java层代码调用c层代码的目的.JNI注册分为静态注册和动态注册两种,静态注册是通过固定格式方法名进行关联,动态 ...

随机推荐

  1. Java关键字break、continue 、return的区别,嵌套循环,数组的概念以及数组案例

    一.关键字 break.continue .return的区别 1.break : 用于在switch..case中放置语句块穿透, ​ 用于跳出循环 // 从1-100 遇到7的倍数 break f ...

  2. C++面试八股文:了解位运算吗?

    某日二师兄参加XXX科技公司的C++工程师开发岗位第12面: 面试官:了解位运算吗? 二师兄:了解一些.(我很熟悉) 面试官:请列举以下有哪些位运算? 二师兄:按位与(&).按位或(|).按位 ...

  3. NameError: name 'List' is not defined

    当在python出现该问题是,使用from typing import List.

  4. 你的专属音乐生成器「GitHub 热点速览」

    如果你制作视频,一定会碰到配乐的问题.虽然网上找的一些免费配乐能勉强满足需求,但是如果有个专属的配乐生成器,根据你的视频画面生成对应配乐是不是不错呢?audiocraft 也许能帮助你,把相关画面用文 ...

  5. 基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发

    基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发 项目简介:目标是开发一个跨平台的AI聊天和其他功能的客户端平台.目的来学习和了解Avalonia.将这个项目部署 ...

  6. 【问题解决】docker版本v23.0后,构建Dockerfile中FROM私库镜像报错构建失败

    问题情况 Docker版本在v23.0以后,只要Dockerfile中FROM的私库镜像不存在本地,就会报错: # 我本地是v24.0.2版本Docker [root@localhost ipd]# ...

  7. Win32编程

    WIN32 malloc函数的底层实现是Win32API 字符编码 原始的ASCII编码最多能表示127个符号 0-7F(十六进制) 缺点:表示的符号太少了 ASCII编码的扩展:GB2312或GB2 ...

  8. Nginx TCP 负载均衡:stream 模块配置

    工作上遇到需要用nginx做负载均衡,参考了前同事留下的作业顺利搞定,感觉这块很有意义写篇文档记录. 参考:nginx tcp负载均衡(Stream模块)配置说明 参考:利用nginx进行TCP负载均 ...

  9. Java并发(十三)----共享存在的问题

    1.小故事 老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快 小南.小女(不同的线程)来使用这个算盘来进行一些计算,并按照时间给老王支付费用 但小南不能一天24小时使用算盘 ...

  10. 如何编写难以维护的React代码?耦合组件

    如何编写难以维护的React代码?耦合组件 在许多项目中,我们经常会遇到一些难以维护的React代码.其中一种常见的情况是:子组件直接操作父组件方法,从而导致父子组件深度耦合.这样的实现让子组件过于依 ...