Android Studio NDK 入门教程--Java与C++之间的类型签名
Posted Wastrel_xyz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Studio NDK 入门教程--Java与C++之间的类型签名相关的知识,希望对你有一定的参考价值。
概述
本文主要介绍Java与C++通信时函数的签名关系
方法签名
我们可以在生成的头文件中看到每个方法上面都有如下注释:
/*
* Class: com_example_wastrel_hellojni_HelloJNI
* Method: getFormCString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_wastrel_hellojni_HelloJNI_getFormCString
(JNIEnv *, jclass);
其中前两个注释很容易理解,第三个就是方法签名,为什么会有方法签名这种东西呢?
这是因为Java这边支持函数重载,即虽然参数不一样,但是方法名一样,那么在JNI层它们的方法名都会是一样的,那JNI也会犯迷糊了,得找哪个呢?
不过也正是因为其参数类型是不一样的,所以就出现了方法签名,利用方法签名和方法名来唯一确定一个JNI函数的调用。既然方法签名是基于参数类型的不同而形成的,首先要知道Java各数据类型对应的签名是什么,也就是所谓的类型签名。
类型签名转换表
jni.h里面定义了这样一套规则:
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 | J |
float | F |
double | D |
void | V |
类 | L全限定名; |
数组 | [类型签名 |
注意:上面的类后面是有一个分号的。
如何计算一个方法的类型签名
Java函数的类型签名是根据函数的参数类型以及返回类型所决定的,参数类型放在括号里面返回类型紧跟在括号外。
//native测试方法声明
public static native String getFormCString();
//三个重载方法
public static native int TypeTest(boolean a,short b,long c,char d);
public static native Objects TypeTest(Date date,byte []m,HelloJNI k);
public static native Long Test(Character k,Double m);
//执行生成头文件命令
/*
* Class: com_example_wastrel_hellojni_HelloJNI
* Method: getFormCString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_wastrel_hellojni_HelloJNI_getFormCString
(JNIEnv *, jclass);
/*
* Class: com_example_wastrel_hellojni_HelloJNI
* Method: TypeTest
* Signature: (ZSJC)I
*/
JNIEXPORT jint JNICALL Java_com_example_wastrel_hellojni_HelloJNI_TypeTest__ZSJC
(JNIEnv *, jclass, jboolean, jshort, jlong, jchar);
/*
* Class: com_example_wastrel_hellojni_HelloJNI
* Method: TypeTest
* Signature: (Ljava/util/Date;[BLcom/example/wastrel/hellojni/HelloJNI;)Ljava/util/Objects;
*/
JNIEXPORT jobject JNICALL Java_com_example_wastrel_hellojni_HelloJNI_TypeTest__Ljava_util_Date_2_3BLcom_example_wastrel_hellojni_HelloJNI_2
(JNIEnv *, jclass, jobject, jbyteArray, jobject);
/*
* Class: com_example_wastrel_hellojni_HelloJNI
* Method: Test
* Signature: (Ljava/lang/Character;Ljava/lang/Double;)Ljava/lang/Long;
*/
JNIEXPORT jobject JNICALL Java_com_example_wastrel_hellojni_HelloJNI_Test
(JNIEnv *, jclass, jobject, jobject);
通过以上代码可以可以看出,重载的方法生成的头文件后函数名后面都追加参数的类型签名,并且‘/’被替换成了下划线‘_’,‘;’被替换成了数字‘2’;‘[’被替换成了数字‘3’。在签名中()里面表示方法的参数,紧接着的是返回类型对应的签名。可以看到String getFromCString
因为没有参数,所以()里面什么都没有,但其有一个返回参数String,String并不是Java的基础类型,String的全称是java.lang.String
,根据签名规则就是Ljava/lang/String;
,因此该方法的签名是()Ljava/lang/String
。这里需要注意,如果一个Java函数没有返回即void,那么对应的返回类型签名就是V。
其余函数有兴趣可以根据上述规则推理,我相信各位程序员的推理能力,这里就不一一讲解。
后记
方法签名是为了便于Java与native代码的相互访问,后面通过C++调用Java代码的时候,方法签名尤为重要。在传递复杂类型的时候相对较为麻烦,在实际使用中并不建议传递复杂对象。这里说一下Java方法重载,在编写native函数的时候不建议使用重载,重载的方法名称很长,辨识度也不高。更建议在java中预处理重载的调用。例如:
public class NativeFunc
public String Func(String str)
return native_func1(str);
public String Func(int i)
return native_func2(i);
public native String native_func1(String str);
public native String native_func2(int i);
以上是关于Android Studio NDK 入门教程--Java与C++之间的类型签名的主要内容,如果未能解决你的问题,请参考以下文章
Android Studio NDK 入门教程--优雅的在C++中输出Logcat
Android Studio NDK 入门教程--JNI动态注册本地方法
Android Studio NDK 入门教程--Java与C++之间的类型签名
Android Studio NDK 入门教程--Java对象的传递与修改