【转】对于JNI方法名,数据类型和方法签名的一些认识

 

之前一直用jni,但是没有考虑Java重载函数,如何在jni-C++里命名,今天看到一篇文章,讲到了类型签名。

原文链接:http://www.2cto.com/kf/201405/302263.html

我们知道,利用javah生成的c/c++头文件的时候,会对java中定义的 native 函数生成对应的jni层函数,如下:

1
2
3
4
5
6
7
/*
 * Class:     com_lms_jni_JniTest
 * Method:    getTestString
 * Signature: ()Ljava/lang/String;
 */ 
JNIEXPORT jstring JNICALL Java_com_lms_jni_JniTest_getTestString 
  (JNIEnv *, jobject);

我们可以看到方法名是以Java_com_lms_jni等开头的,还有什么所谓的Signature,那这些其实都是什么意思呢,今天我们就来简单地认识一下。

JNI 命名规则

对于传统的JNI编程来说,JNI方法跟Java类方法的名称之间有一定的对应关系,要遵循一定的命名规则,如下:

1) 前缀: Java_
2) 类的全限定名,用下划线进行分隔(_):com_lms_jni_JniTest
3) 方法名:getTestString  
3) jni函数指定第一个参数: JNIEnv *
4) jni函数指定第二个参数: jobject
5) 实际Java参数: jstring, jint ....
6) 返回值的参数 : jstring, jint.... 所以对于在Java类 com.lms.jni.HwDemo中的一个方法:

1
public native String addTail(String tail);

其对应的jni层的方法如下:

1
jstring Java_com_lms_jni_HwDemo_addTail(JNIEnv * e, jobject clazz, jstring tail);

如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。
注意,我们也可以利用函数注册的方法,将Java层的方法名跟JNI层的方法名的对应关系保存起来,注册到DVM中,就不需要这样的命名规范了。

JNI 数据类型

我们知道Java的数据类型是跟C/C++的数据类型是不一样的,而JNI是处于Java和Native本地库(大部分是用C/C++写的)中间的一层,JNI对于两种不同的数据类型之间必须做一种转换,所以在JNI跟Java之间就会有数据类型的对应关系。 在JNI中,提供了以下各种数据类型,可以分为原生类型和引用类型: 对于原生类型有:jchar, jbyte, jshort, jint, jlong, jfloat, jdouble, jboolean,其与java端的数据类型对应如下表:

java jni
char jchar
byte jbyte
short jshort
int jint
long jlong
float jfloat
double jdouble
boolean jboolean

对于引用类型则有:jobject, jstring, jthrowable, jclass, jarray, 以及继承于jarray,对应于其原生类型的8种jarray和jobjectarray。

知道了不同的数据类型的转换关系,我们就知道在什么情况下,应该对数据进行怎么样的处理。

JNI方法签名

为什么会有方法签名这种东西呢?这是因为Java这边支持函数重载,即虽然参数不一样,但是方法名一样,那么在JNI层它们的方法名都会是一样的,那JNI也会犯迷糊了,得找哪个呢?
不过也正是因为其参数类型是不一样的,所以就出现了方法签名,利用方法签名和方法名来唯一确定一个JNI函数的调用。
既然方法签名是基于参数类型的不同而形成的,首先要知道Java各数据类型对应的签名是什么,也就是所谓的类型签名,
在jni.h文件中就已经定义了这样一套规则,如下:

1
2
3
4
5
6
7
8
9
10
11
typedef union jvalue {
    jboolean    z;
    jbyte       b;
    jchar       c;
    jshort      s;
    jint        i;
    jlong       j;
    jfloat      f;
    jdouble     d;
    jobject     l;
} jvalue;

对应于Java端的数据类型,我们也可以看一下下面的表:

Java 类型 类型签名
boolean Z
byte B
char C
short S
int I
long L
float  F
double D
L全限定名;,比如String, 其签名为Ljava/lang/util/String;
数组 [类型签名, 比如 [B

对于上面的类,要注意其后面还有一个分号。
而对一个方法,其签名就是其参数类型签名和返回值类型签名的字符串,其形式如下: 
(类型签名1类型签名2...)返回值类型签名 
每个类型签名之间是没有空格的,下面看看两个例子:

有方法 1):

1
public string addTail(String tail, int index)

其对应的签名如下:

1
(Ljava/util/String;I)Ljava/util/String;

方法 2):

1
public int addValue(int index, String value,int[] arr)

其对应的签名如下:

1
(ILjava/util/String;[I)I

相信通过这两个例子,大家也能够了解了方法签名是什么样的形式了吧,对于JNI这些奇形怪状的表示形式也有一定的了解了。

结束。

【转】对于JNI方法名,数据类型和方法签名的一些认识的更多相关文章

  1. Android有关JNI 学习(两)为JNI方法名称,数据类型和方法签名的一些知识

    我们知道,使用javah产生c/c++当在头文件,将java定义 native 功能,以产生相应jni层功能,如下面: /* * Class: com_lms_jni_JniTest * Method ...

  2. [No000085]C#反射Demo,通过类名(String)创建类实例,通过方法名(String)调用方法

    using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Sy ...

  3. Android深入理解JNI(二)类型转换、方法签名和JNIEnv

    相关文章 Android深入理解JNI系列 前言 上一篇文章介绍了JNI的基本原理和注册,这一篇接着带领大家来学习JNI的数据类型转换.方法签名和JNIEnv. 1.数据类型的转换 首先给出上一篇文章 ...

  4. 子类重载父类的方法“parent::方法名”转于 恩聪PHP学习教程

    在PHP中不能定义重名的函数,也包括不能再同一个类中定义重名的方法,所以也就没有方法重载.单在子类中可以定义和父类重名的方法,因为父类的方法已经在子类中存在,这样在子类中就可以把从父类中继承过来的方法 ...

  5. 子类重载父类的方法“parent:方法名”

    在PHP中不能定义重名的函数,也包括不能再同一个类中定义重名的方法,所以也就没有方法重载.单在子类中可以定义和父类重名的方法,因为父类的方法已经在子类中存在,这样在子类中就可以把从父类中继承过来的方法 ...

  6. 在IE中,JS方法名和input的name重名时,调用该方法无效

    在IE中,JS方法名和input的name重名时,调用该方法无效.提示:网页错误详细信息 用户代理: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1 ...

  7. c# 获取方法所在的命名空间 类名 方法名

    平时我们在记录日志的时候难免会需要直接记录当前方法的路径,以便查找,但是每次都输入方法名称非常的繁琐,同时如果修改了方法名称也要去手动修改日志内容,真的是劳命伤财啊,所以有了如下方法则可解决我们的大难 ...

  8. C# 获取方法所在的 命名空间 类名 方法名

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  9. html调用js提示方法名 is not defined处理方法

    解决办法(方法名 is not defined): dosave=function(){ alert("方法名在前"); } 下面这种写法有时候会出现错误: function do ...

随机推荐

  1. brctl 的使用

    brctl  作用: 用来进行以太网桥接(bridge)的管理 主要用法如下: root@hbg:/# brctl --helpBusyBox v1.22.1 (2016-02-24 11:41:04 ...

  2. 判断括号字符串是否为合法+求n对括号的所有组合

    n对括号的有效组合数 参考:https://zh.wikipedia.org/wiki/%E5%8D%A1%E5%A1%94%E5%85%B0%E6%95%B0 import java.util.Ar ...

  3. Lightoj 1066 Gathering Food (bfs)

    Description Winter is approaching! The weather is getting colder and days are becoming shorter. The ...

  4. 【Loadrunner】初学Loadrunner——录制脚本、回放、以及优化

    一.脚本录制(录制) 打开Loadrunner > 选择创建/编辑脚本 > NewScript > 选择协议(单协议.多协议) > Strart Recording >选 ...

  5. ejabberd聊天室离线消息

    首先,xmpp服务器是基于ejabberd.离线消息模块是mod_interact,原地址地址:https://github.com /adamvduke/mod_interact: 修改后实现群聊离 ...

  6. NYOJ-791 Color the fence (贪心)

    Color the fence 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 Tom has fallen in love with Mary. Now Tom w ...

  7. mybatis遇见的奇葩问题(返回null)

    1.问题描述 select 语句没有问题,执行完毕后通过日志也可以看出 select到数据了,但是拿到的值就是null 2.原因 原来是有人将对象变量命名给改了,导致select到结果后不能映射成为对 ...

  8. C语言语法tips(不断更新)

    语法虽然琐碎,犯了低级错误代价可就大了,列出一些容易混淆概念,避免以后出错 sizeof和strlen的区别在于:1.sizeof是运算符,语言支持的,strlen可以求malloc出来的字符串的长度 ...

  9. nginx安装与应用

    一.nginx的安装与启动: 1.安装依赖库.nginx的一些模块需要依赖其他第三方库,通常有pcre库(perl compatible regular expression,perl兼容正则表达式, ...

  10. ==、equals、hashCode区别?

    [==.equals().hashCode()区别?] 1)== 运算符用来比较两个变量的值是否相等. 即该运算符用于比较变量对应得内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是 ...