Java Native Interface 二 JNI中对Java基本类型和引用类型的处理
本文是《The Java Native Interface Programmer’s Guide and Specification》读书笔记
Java编程里会使用到两种类型:基本类型(如int,float等)和引用类型(如class,instance,arrays),JNI编程里对这两种的类型的处理方法也是不一样的。
JNI定义了与Java的基本类型和引用类型相对应的C/C++类型:
Java类型 | 本地类型(JNI中使用) |
---|---|
boolean | jboolean |
int | jint |
float | jfloat |
byte | jbyte |
char | jchar |
short | jshort |
long | jlong |
double | jdouble |
Java中所有对象都是Object类的子类,在JNI中与之对应的为jobject类,所有的类型都是jobject类的子类,直接继承自jobject 的引用类型:
Java类型 | 本地类型 |
---|---|
java.lang.Class | jclass |
java.lang.String | jstring |
arrays | jarray |
java.lang.Throwable | jthrowable |
其中数组又会有其他的子类型,如Java中的int[] 对应到JNI中为jintArray,Object[]对应为jobjectArray[]等;
在使用C++时,类的继承的语法为
class _jobjct{};
class _jclass:public_jobjct{};//公有继承
同时在JNI中会使用类标识符来表示Java中的类或接口。数组用'['来标识,如int[]在JNI中用'[I'来标识,三维数组double[][][],用['[[[D'来标识;下面是JNI中常用基本类型的标识符与对应的Java类:
成员域标识符 | Java 类型 |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
JNI中引用类型的标识符以字符'L'开始,并以';'结束,但数组的标识符与前面的基本类型的标识符相同;
标识符 | Java类型 |
---|---|
"Ljava/lang/String;" | String |
"[I" | int[] |
"[Ljava/lang/Object;" | Object[] |
在JNI中方法的标识符里,方法所含的参数之间是没有空格隔开的,并用字符"V"作为void方法的返回标识;构造函数一般使用"V"作为返回值,"init"作为名字;
方法标识符 | Java方法 |
---|---|
"()Ljava/lang/String; " | String f() |
"(ILjava/lang/Class;)J" | long f(int i,Class c) |
"([B)V" | String(byte[]bytes) |
在了解完JNI中对应的类型与标识符后,接下来就是怎样使用它们了。
String类型的使用
在实现本地方法时,必须使用JNI的方法将对应的jstring对象类型转型为c/c++可以识别的string 对象,否则在调用这个本地方法时会导致Java虚拟机崩溃;
假设有一个本地方法,在Java里声明为:
public native String getLine(String promt);
则你在实现这个方法时,不能这样写:
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{/* ERROR: incorrect use of jstring as a char* pointer */printf("%s", prompt);...
}
你可以这样写:
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{char buf[128];const jbyte *str;str = (*env)->GetStringUTFChars(env, prompt, NULL);//必须要记得检查JNI方法的返回值,因为JVM在执行时需要分配内存,可能存在内存分配失败的情况if (str == NULL) {return NULL; /* OutOfMemoryError already thrown */}printf("%s", str);//当使用完JNI方法返回的对象后,调用相应的Release方法释放掉对应的内 存,忘记使用Release方法可能会导致内存泄漏(*env)->ReleaseStringUTFChars(env, prompt, str);/* We assume here that the user does not type more than* 127 characters */scanf("%s", buf);return (*env)->NewStringUTF(env, buf);
}
jni中的可以对String(jstring)对象使用的方法总结:
方法名 | 方法描述 |
---|---|
GetStringChars,ReleaseStringChars | 获取或释放一个指向Unicode编码的字符串内容的指针,可能会返回一个字符串的拷贝 |
GetStringUTFChars,ReleaseStringUTFChars | 获取或释放一个指向UTF-8编码的字符串内容的指针,可能会返回一个字符串的拷贝 |
GetStrinLength | 返回字符串里Unicode编码的字符的个数 |
GetStringUTFLength | 返回字符串里UTF-8编码的字符的个数 |
NewString | 创建一个包含给定的Unicode编码的C字符串的所有字符的java.lang.String实例 |
NewStringUTF | 创建一个包含给定的UTF-8编码的C字符串的所有字符的java.lang.String实例 |
GetStringCritical,ReleaseStringCritical | 获取一个指向Unicode编码的字符串内容的指针,可能返回一个字符串的拷贝。并且本地代码在调用Get/ReleaseStrinCritical这对方法时,不能阻塞。 |
GetStringUTFRegion,SetStringUTFRegion | 从一个预先分配的UTF-8格式的C的缓冲区拷贝字符串内容(或将字符串内容写入缓冲区中) |
Arrays类型的使用
JNI对普通数组(基本类型的数组,如int[],float[])和对象数组的处理方法是不一样的。下面以简单的例子来说明:
1 普通的数组的使用
求一个数组的和的例子:Java Class为:
class IntArray {private native int sumArray(int[] arr);//jni方法,求数组的和public static void main(String[] args) {IntArray p = new IntArray();int arr[] = new int[10];for (int i = 0; i < 10; i++) {arr[i] = i;}int sum = p.sumArray(arr);System.out.println("sum = " + sum);}static {System.loadLibrary("IntArray");}
}
Java的Arrays在JNI中用jarrays和它的子类,如jintArray来表示,就像jstring不是C字符串的类型,jarrays也不是C的数组类型,因此,你不能在实现JNI方法时,直接使用jarrays的引用,下面是错误的JNI方法的编写:
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{int i, sum = 0;for (i = 0; i < 10; i++) {sum += arr[i];}
}
正确的JNI的方法应该为:
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{jint buf[10];jint i, sum = 0;(*env)->GetIntArrayRegion(env, arr, 0, 10, buf);for (i = 0; i < 10; i++) {sum += buf[i];}return sum;
}
也可以这样写:
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{jint *carr;jint i, sum = 0;carr = (*env)->GetIntArrayElements(env, arr, NULL);if (carr == NULL) {return 0; /* exception occurred */}for (i=0; i<10; i++) {sum += carr[i];}(*env)->ReleaseIntArrayElements(env, arr, carr, 0);return sum;
}
JNI中可以对基本类型数组使用的方法有:
:表示需要用基本类型来替代,如GetArrayRegion,就可以有GetIntArrayRegion,GetFloatArrayRegion等;
方法名 | 方法描述 |
---|---|
GetArrayRegion,SetArrayRegion | 得到基本类型的数组的内容,或将内容写入预先分配的C的缓冲区里 |
GetArrayElements,ReleaseArrayElements | 获得一个指向基本类型数组的内容的指针,可能会返回一个数组的拷贝 |
GetArrayLength | 返回数组的大小 |
NewArray | 创建一个给定长度的数组 |
GetPrimitiveArrayCritical,ReleasePrimitiveArrayCritical | 获得或释放指向基本类型数组的内容的指针 |
2 对象数组的使用:
JNI提供了许多对方法来得到对象数组。GetObjectElement
方法会返回一个给定位置的元素,SetObjectElement
方法更新给定位置的元素。但我们不能一次性就得到(复制)所有的对象数组里的元素。下面还是以简单的例子来说明:
Java Class为:
class ObjectArrayTest {//本地方法,用来生成一个给定大小的二维矩阵private static native int[][] initInt2DArray(int size);public static void main(String[] args) {int[][] i2arr = initInt2DArray(3);for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {System.out.print(" " + i2arr[i][j]);}System.out.println();}}static {System.loadLibrary("ObjectArrayTest");}
}
本地方法的实现为:
JNIEXPORT jobjectArray JNICALL
Java_ObjectArrayTest_initInt2DArray(JNIEnv *env,jclass cls,int size)
{jobjectArray result;int i;//获得一个元素类型(Int)的Class引用,类似于Java中得到某一类型的类加载器jclass intArrCls = (*env)->FindClass(env, "[I");if (intArrCls == NULL) {return NULL; /* exception thrown */}//生成一个元素类型为intArrCls的数组,这个方法只能生成一维数组result = (*env)->NewObjectArray(env, size, intArrCls,
NULL);if (result == NULL) {return NULL; /* out of memory error thrown */}for (i = 0; i < size; i++) {jint tmp[256]; /* make sure it is large enough! */int j;//生成数组里存放的元素(仍然为一个数组)jintArray iarr = (*env)->NewIntArray(env, size);if (iarr == NULL) {return NULL; /* out of memory error thrown */}for (j = 0; j < size; j++) {tmp[j] = i + j;}//用tmp里的元素填充iarr数组,使用的是基本类型数组的方法(*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);//将iarr作为数组元素填充到result数组相应位置中,使用的是对象数 组的方法(*env)->SetObjectArrayElement(env, result, i, iarr);//释放到对iarr对象的引用(*env)->DeleteLocalRef(env, iarr);}//二维数组就是数组里存放的元素仍然为数组,返回一个对象数组return result;
}
转载于:https://www.cnblogs.com/WoodJim/p/4794772.html
Java Native Interface 二 JNI中对Java基本类型和引用类型的处理相关推荐
- Java Native Interface 六JNI中的异常
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...
- 【转】JNI(Java Native Interface)的简介
因为刚刚接触android和java平台,对JNI到底是什么,还不是很了解,所以从CSDN转载了一篇文章,以便自己对JNI有一个认识,也跟大家分享一下. JNI是Java Native Interfa ...
- JNI (Java Native Interface)是什么
JNI是Java Native Interface的缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代 ...
- 转】JNI(Java Native Interface)的简介
JNI 是Java Native Interface 的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言 ...
- Android JNI(Java Native Interface)技术介绍
Android平台上的JNI技术介绍 JUL 15TH, 2013 | COMMENTS NDK简介 Android是由Google领导开发的操作系统,Android依靠其开放性,迅速普及,成为目前最 ...
- java native 接口_Java本地接口--Java Native Interface (JNI)
一.方法介绍 java native方法是指本地方法,当在方法中调用一些不是由java语言写的代码或者在方法中用java语言直接操纵计算机硬件时要声明为native方法. java中,通过JNI(Ja ...
- Java的数据类型-基本类型和引用类型
道生一,一生二,二生三,三生万物------老子 二进制是道.基本类型是一.引用类型是二.框架是三.软件应用是万物------小虎哥. 0.基本类型和引用类型的区别 Java中的数据类型分为 基本类型 ...
- java面向对象(类与对象,局部变量成员变量,基本类型和引用类型作为参数传递)...
一.类和对象的区别 类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体 可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系.类用于描述 ...
- javascript变量中基本类型和引用类型的详解解读
前言: Javascript语言中的变量和其他语言的变量有很大区别,javascript松散类型的本质,决定了它只是在特定时间时间保存特定值得名字而已.由于不存在定义某个变量必须保存何种数据类型值的规 ...
最新文章
- 如何教计算机认识手写数字(下)
- 【本人秃顶程序员】使用Spring Cloud Stream和RabbitMQ实现事件驱动的微服务
- [机器学习]梯度提升决策树--GBDT
- 快节奏多人游戏同步:技术与算法的实现
- 利用python爬虫(part15)--cookie模拟登陆
- 让Team Foundation Server/TFS自动记住用户名密码解决方案
- spacy 报错 gold.pyx in spacy.gold.GoldParse.__init__() 解决方案
- Dapper Sqlpara where in
- idea创建springcloud项目_新手向,十分钟快速创建 Spring Cloud 项目
- 设计模式系列——单例模式
- JSP技术的学习总结
- 原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧
- 真彩色图像数据量 计算_计算机基础:图形、图像相关知识笔记
- 数据流图DFD --详细介绍
- Adobe Premiere Pro 2020
- ERP软件主要的作用有哪些?
- 来2019全球智博会 见证AI创新未来 1
- curl怎么输出赋值_PLC时间日期怎么读取?
- yml和yaml配置文件语法
- 环境变量配过了,依然找不到路径,办法
热门文章
- CTFshow 信息收集 web20
- mysql取出数据外键_mysql数据表有外键,应注意的几点(目前学习所获得的经验)...
- [ Linux ] [ OS ] [ memory ] Linux 如何查看系統硬體的記憶體(RAM)資訊
- EM上的按钮是方框的问题
- LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)
- go的http服务报错accept4: too many open files
- Struts2-2.了解struts.xml的查找顺序
- 一种新的Heap区溢出技术分析[转贴]
- 【Nutch2.2.1基础教程之2.1】集成Nutch/Hbase/Solr构建搜索引擎之一:安装及运行【单机环境】...
- WCF RIA Service中 POCO实体含有复杂类型怎么处理?