人间观察

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

在前面的几篇文章中有涉及到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: Ipublic long size;descriptor: Jpublic com.bj.gxz.jniapp.methodfield.AppInfo(java.lang.String);descriptor: (Ljava/lang/String;)Vpublic com.bj.gxz.jniapp.methodfield.AppInfo(java.lang.String, int);descriptor: (Ljava/lang/String;I)Vpublic java.lang.String getVersionName();descriptor: ()Ljava/lang/String;public void setVersionName(java.lang.String);descriptor: (Ljava/lang/String;)Vpublic int getVersionCode();descriptor: ()Ipublic void setVersionCode(int);descriptor: (I)Vpublic void setSize(long);descriptor: (J)Vpublic long getSize();descriptor: ()Jpublic 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)Vpublic void setVersionName(java.lang.String);descriptor: (Ljava/lang/String;)V  

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

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

  1. JNI开发笔记(七)--aar库的生成和调用

    aar库的生成和调用 引 前言 1. 新建一个空工程 2. 新建一个Module 3. 移植JNI工程到Module中 4. 生成aar库与so库 5. 在另一个工程中调用aar库 引 JNI开发笔记 ...

  2. Android蓝牙开发系列文章-蓝牙设备类型知多少?

    在写<Android蓝牙开发系列文章-蓝牙音箱连接>时,计划细化出一篇讲解蓝牙设备类型的文章,现在它来了~ 阅读其他内容,可以点击<Android蓝牙开发系列文章-策划篇>,或 ...

  3. Android商城开发系列

    Android商城开发系列(一)--开篇 Android商城开发系列(二)--App启动欢迎页面制作 Android商城开发系列(三)--使用Fragment+RadioButton实现商城底部导航栏 ...

  4. android 相机编程,Android相机开发系列

    Android Camera Develop Series 简介 Android相机开发系列文章循序渐进,教你从一个没有任何功能的相机APP开始,逐步完善实现一般相机APP的各种功能,甚至还能拿来做图 ...

  5. Android蓝牙开发系列文章-蓝牙mesh(一)

    在<Android蓝牙开发系列文章-策划篇>中我们对蓝牙专题的内容进行整体规划,现在让我们一点点揭开他的面纱~ 本文是关于蓝牙mesh的首篇文章,由好友CSDN博主yk150915提供,在 ...

  6. Android Camera开发系列(下)——自定义Camera实现拍照查看图片等功能

    Android Camera开发系列(下)--自定义Camera实现拍照查看图片等功能 Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 上 ...

  7. Android蓝牙开发系列文章-蓝牙音箱连接

    经过一段时间的折腾,我的Android Studio终于可以正常工作了,期间遇到的坑记录在了文章<创建Android Studio 3.5第一个工程遇到的坑>. 我们在<Androi ...

  8. Android自定义控件开发系列(零)——基础原理篇

    在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇"基础原理篇",直接进入正题吧-- 首先的问题是:在Android项目开发中,什么时候 ...

  9. Android 快速开发系列 打造万能的ListView GridView 适配器

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写 ...

最新文章

  1. 身份证号码对应地区-官方措辞:行政区划代码
  2. 索尔维会议记录软件测试,索尔维会议
  3. Ibatis查询条件对于特殊字符的处理方法
  4. 当.NET遇到SYBASE
  5. SpringCloud学习路线
  6. Spring Cloud
  7. 局域网怎么修改其它计算机ip,电脑局域网怎么更改ip
  8. 关于Git这一篇就够了
  9. cocos2d-x中使用CCSprite拼接有缝隙
  10. 【模型结构绘制】深度学习神经网络模型结构图绘制工具及方法总结【写论文必备】
  11. Linux积累 - scp 远程复制 加端口
  12. 指针数组和指向指针的指针
  13. c++基础知识点(6)类的继承,构造,析构顺序,虚继承等
  14. 90后小伙用果酱画画:花鸟鱼虫活灵活现(图)
  15. Linux(入门基础):04---文件的压缩、解压、打包(gzip、bzip2、xz、tar)
  16. FFmpeg浅尝辄止(四)——音频的解码和编码
  17. java 修改gps,改机 - 从源码着手任意修改GPS地理位置
  18. 输入输出系统:M/M/1排队系统例题
  19. PACE——深度神经网络测试的实用准确度估计方法
  20. 配置注册表数据库损坏

热门文章

  1. ehcache入门基础示例
  2. Android studio 如何导入并引用Library工程
  3. Hyper-V Server 存储分层
  4. 教程-TObjectList.Clear、TStringList.Clear方法对象有没有被释放
  5. LastPass 的开源替代品
  6. 空位補零,你會選擇哪種方式?
  7. javascript小技巧(转自DooIT)http://www.cnblogs.com/ttyp/archive/2004/11/15/63900.html
  8. 操作日志和系统日志分类记录
  9. 简述数学建模的过程_【数学建模的基本工作流程】作业帮
  10. mysql查看脚本错误位置_记一次mysql启动不了查找经历