Android-JNI开发系列《七》补充jni与java的数据类型的对应关系和数据类型描述符

人间观察

人只有不为生存而烦恼的时候,才会追求真正想要的东西。

在前面的几篇文章中有涉及到Java和JNI的通信,比如异常回调,Java和JNI的互相调用等。其中都免不了在通信过程中需要知道Java基本数据类型,引用类型和JNI的对应关系以及基本数据类型,引用类型的类型描述符,才能够通信和使用。

这个是很重要的,是基础,有必要单独来记录下。

在 JNI 开发中,Java 的数据类型并不是直接在 JNI 里使用的,例如 int 就在JNI中是使用 jint 来表示的。

数据类型对应

基本数据类型

Java与Native映射关系如下表所示:

Java类型 Native 类型 Description
boolean jboolean unsigned 8 bits
byte jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
int jint signed 32 bits
long jlong signed 64 bits
float jfloat 32 bits
double jdouble 64 bits
void void not applicable

引用数据类型

外面的为JNI中的,括号中的Java中的。

  • jobject
    • jclass (java.lang.Class objects)
    • jstring (java.lang.String objects)
    • jarray (arrays)
      • jobjectArray (object arrays)
      • jbooleanArray (boolean arrays)
      • jbyteArray (byte arrays)
      • jcharArray (char arrays)
      • jshortArray (short arrays)
      • jintArray (int arrays)
      • jlongArray (long arrays)
      • jfloatArray (float arrays)
      • jdoubleArray (double arrays)
  • jthrowable (java.lang.Throwable objects)

上面的层次中的jni的引用类型代表了继承关系,jbooleanArray继承jarray,jarray继承jobject,最终都继承jobject。

示例

java 层
public native void data(byte b, char c, boolean bool, short s, int i, float f, double d, long l, float[] floats);
jni层
extern "C"
JNIEXPORT void JNICALL
Java_com_bj_gxz_jniapp_data_JNIData_data(JNIEnv *env, jobject thiz, jbyte b, jchar c,
                                         jboolean j_bool,
                                         jshort s, jint i, jfloat f, jdouble d, jlong l,
                                         jfloatArray floats) {
    LOG_D("byte=%d", b);
    LOG_D("jchar=%c", c);
    LOG_D("jboolean=%d", j_bool);
    LOG_D("jshort=%d", s);
    LOG_D("jint=%d", i);
    LOG_D("jfloat=%f", f);
    LOG_D("jdouble=%lf", d);
    LOG_D("jlong=%lld", l);

    jfloat *float_p = env->GetFloatArrayElements(floats, nullptr);
    jsize size = env->GetArrayLength(floats);
    for (int index = 0; index < size; index++) {
        LOG_D("floats[%d]=%lf", index, *(float_p++));
    }
    env->ReleaseFloatArrayElements(floats, float_p, 0);
}

输出日志

2020-10-30 15:00:24.819 2588-2588/com.bj.gxz.jniapp D/JNI: byte=100
2020-10-30 15:00:24.819 2588-2588/com.bj.gxz.jniapp D/JNI: jchar=A
2020-10-30 15:00:24.819 2588-2588/com.bj.gxz.jniapp D/JNI: jboolean=1
2020-10-30 15:00:24.819 2588-2588/com.bj.gxz.jniapp D/JNI: jshort=100
2020-10-30 15:00:24.819 2588-2588/com.bj.gxz.jniapp D/JNI: jint=100
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: jfloat=100.000000
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: jdouble=100.000000
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: jlong=100
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: floats[0]=1.000000
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: floats[1]=2.100000
2020-10-30 15:00:24.820 2588-2588/com.bj.gxz.jniapp D/JNI: floats[2]=3.300000

关于java复杂对象的传递可以参考上篇文章。

描述符/签名

我们平时定义的int,float,String等类型在JVM虚拟机中,存储数据类型的名称时是使用描述符来存储,它们有固定的规则/语法。如下表格:

Java类型 类型描述符/签名
int I
long J
byte B
short S
char C
float F
double D
boolean Z
void V
数组 [
二维数组 [[
其他引用类型 L+类全名+;

如何查看描述符/签名

可以使用jdk提供的javap -s A.class 命令,-s输出内部类型签名。A.class为class的全路径。试下javap -s AppInfo.class AppInfo.classAppInfo.java编译后的.class文。可以获取任何一个类的成员变量和方法的描述符/签名。

demo:
方法或者成员变量下面的descriptor就是对应它的描述符/签名。

B000000073160:methodfield guxiuzhong$ pwd
/Users/guxiuzhong/Desktop/JNIAPP/app/build/intermediates/javac/debug/classes/com/bj/gxz/jniapp/methodfield
B000000073160:methodfield guxiuzhong$ javap -s  AppInfo.class
Compiled from "AppInfo.java"

public class com.bj.gxz.jniapp.methodfield.AppInfo implements java.io.Serializable {
  public int versionCode;
    descriptor: I
  public long size;
    descriptor: J
  public com.bj.gxz.jniapp.methodfield.AppInfo(java.lang.String);
    descriptor: (Ljava/lang/String;)V

  public com.bj.gxz.jniapp.methodfield.AppInfo(java.lang.String, int);
    descriptor: (Ljava/lang/String;I)V

  public java.lang.String getVersionName();
    descriptor: ()Ljava/lang/String;

  public void setVersionName(java.lang.String);
    descriptor: (Ljava/lang/String;)V

  public int getVersionCode();
    descriptor: ()I

  public void setVersionCode(int);
    descriptor: (I)V

  public void setSize(long);
    descriptor: (J)V

  public long getSize();
    descriptor: ()J

  public java.lang.String toString();
    descriptor: ()Ljava/lang/String;
}
B000000073160:methodfield guxiuzhong$

类描述符

类描述符的规则是:类全名(包名+类名)将原来的.分隔符换成/ 分隔符。比如

在java代码中的java.lang.String类的类描述符就是java/lang/String

java.io.InputStream类的类描述符就是java/io/InputStream

demo中的AppInfo就是com/bj/gxz/jniapp/methodfield/AppInfo

在jni中获取java的class就是通过类描述符获取,比如:

 jclass cls = env->FindClass("com/bj/gxz/jniapp/methodfield/AppInfo");

成员变量描述符/成员变量签名

  • 基本数据类型的描述符

    基本数据类型就是如表格所示,与上面我们用javap出来的一样。

  • 引用类型的描述符

    当引用类型作为成员变量时,它的规则就是: L类全名; 大写L 英文; 类全名(包名+类名)将原来的.分隔符换成/ 分隔符

比如

在java代码中的java.lang.String类的类描述符就是Ljava/lang/String;

java.io.InputStream类的类描述符就是Ljava/io/InputStream;

demo中的AppInfo就是Lcom/bj/gxz/jniapp/methodfield/AppInfo;

方法描述符/方法签名

规则为: (参数的域描述符的叠加)返回类型描述符,没有返回值的用V(void类型)

比如
java方法void method (int a) 对应的方法签名是 (I)V

java方法int method (byte[ ] bytes) 对应的方法签名是 ([B)I

再比如demo中的

public void setSize(long);
    descriptor: (J)V
    
public void setVersionName(java.lang.String);
    descriptor: (Ljava/lang/String;)V  
    

这玩意要记吗?熟还能生巧,不用死记,最开始可以用javap -s A.class,慢慢的就能写出来了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269