看王择佑老师的JNI视频,学习总结的一些基础知识。

1.JNIEnv

通过JNIEnv的指针能够对Java端的代码进行操作:

a.创建Java对象.

NewObject/NewString/New<Type>Array

b.调用Java对象的方法。

Call<Type>Method/CallStatic<Type>Method

c.获取及设置Java对象的属性。

Get/Set[Static]<Type>Method

2.JNI中通常用JType指代Java环境中的类。

[cpp] view plain copy print?
  1. typedef _jobject *jobject;
  2. typedef _jclass *jclass;
  3. typedef _jthrowable *jthrowable;
  4. typedef _jstring *jstring;
  5. typedef _jarray *jarray;
  6. typedef _jbooleanArray *jbooleanArray;
  7. typedef _jbyteArray *jbyteArray;
  8. typedef _jcharArray *jcharArray;
  9. typedef _jshortArray *jshortArray;
  10. typedef _jintArray *jintArray;
  11. typedef _jlongArray *jlongArray;
  12. typedef _jfloatArray *jfloatArray;
  13. typedef _jdoubleArray *jdoubleArray;
  14. typedef _jobjectArray *jobjectArray;
typedef _jobject *jobject;
typedef _jclass *jclass;
typedef _jthrowable *jthrowable;
typedef _jstring *jstring;
typedef _jarray *jarray;
typedef _jbooleanArray *jbooleanArray;
typedef _jbyteArray *jbyteArray;
typedef _jcharArray *jcharArray;
typedef _jshortArray *jshortArray;
typedef _jintArray *jintArray;
typedef _jlongArray *jlongArray;
typedef _jfloatArray *jfloatArray;
typedef _jdoubleArray *jdoubleArray;
typedef _jobjectArray *jobjectArray;

3.JType都继承自JObject

[cpp] view plain copy print?
  1. class _jobject {};
  2. class _jclass : public _jobject {};
  3. class _jthrowable : public _jobject {};
  4. class _jstring : public _jobject {};
  5. class _jarray : public _jobject {};
  6. class _jbooleanArray : public _jarray {};
  7. class _jbyteArray : public _jarray {};
  8. class _jcharArray : public _jarray {};
  9. class _jshortArray : public _jarray {};
  10. class _jintArray : public _jarray {};
  11. class _jlongArray : public _jarray {};
  12. class _jfloatArray : public _jarray {};
  13. class _jdoubleArray : public _jarray {};
  14. class _jobjectArray : public _jarray {};
class _jobject {};
class _jclass : public _jobject {};
class _jthrowable : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jobjectArray : public _jarray {};

4.jobject

JNIEXPORT void JNICALL Java_com_jue_testnative_TestNative1_hello(JNIEnv *, jobject);

jobject指代的在Java中调用native方法的java类实例

5.获取jclass的方法

a. jclass FindClass(const char *name)

b. jclass GetObjectClass(jobject obj)

6.FindClass会在ClassPath下面寻找类。需要传入完整类名,注意包与包之间用’/'。

jclass class_str = env->FindClass("java/lang/String");

7.jfiledID/jmethodID

在natvie方法中获取/设置字段的值,或者方法调用,需要先获取相应的field/method的ID

[cpp] view plain copy print?
  1. jfieldID GetFieldID(jclass clazz, const char *name, const char *sig)
jfieldID GetFieldID(jclass clazz, const char *name, const char *sig) 
[cpp] view plain copy print?
  1. jmethodID GetMethodID(jclass clazz, const char *name, const char *sig)
jmethodID GetMethodID(jclass clazz, const char *name, const char *sig)

注意sig用来处理函数重载引起的不确定。

然后通过ID获取

[cpp] view plain copy print?
  1. jobject GetObjectField(jobject obj, jfieldID fieldID)
jobject GetObjectField(jobject obj, jfieldID fieldID) 
[cpp] view plain copy print?
  1. jobject CallObjectMethod(jobject obj, jmethodID methodID, ...)
jobject CallObjectMethod(jobject obj, jmethodID methodID, ...)

8.Sin签名含义细节

类型 相应的签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
String Ljava/lang/String
Array [Ljava/lang/Object
Method (para s1,para s2)
 返回值签名

9.javap -s 命令工具可以查看一个类的方法的签名

javap -s xxx.class

10.调用java方法

a.JNIEnv提供了Call<Type>Method,  CallStatic<Type>Method,CallNonvirtual<Type>Method函数(能够实现子类对象调用父类方法的功能)。

b.调用实例方法的三种方法

1>Call<Type>Method(jobject obj, jmethodID id, ...);

[cpp] view plain copy print?
  1. boolean funcation(int i, double d, char c) {
  2. }
  3. env->CallBooleanMethod( obj, id_function , 100L, 3.44, L'3');
boolean funcation(int i, double d, char c) {
}env->CallBooleanMethod( obj, id_function , 100L, 3.44, L'3');

注意java中的int是C++环境中的长整形。L'3'是C++中的宽字符

2>Call<Type>MethodV(jobject obj, jmethodID id,va_list lst);

3>Call<Type>MethodA(jobject obj, jmethodID id, jvalue* v);

jvalue是一个联合体

[cpp] view plain copy print?
  1. typedef union jvalue {
  2. jboolean z;
  3. jbyte    b;
  4. jchar    c;
  5. jshort   s;
  6. jint     i;
  7. jlong    j;
  8. jfloat   f;
  9. jdouble  d;
  10. jobject  l;
  11. } jvalue;
typedef union jvalue {jboolean z;jbyte    b;jchar    c;jshort   s;jint     i;jlong    j;jfloat   f;jdouble  d;jobject  l;
} jvalue;
[cpp] view plain copy print?
  1. jvalue *args = new jvalue[3];
  2. args[0].i = 100L;
  3. args[1].d = 3.44;
  4. args[2].c = L'3';
  5. env->CallBooleanMethodA(obj, id_funcation, args);
  6. delete [] args;
jvalue *args = new jvalue[3];
args[0].i = 100L;
args[1].d = 3.44;
args[2].c = L'3';
env->CallBooleanMethodA(obj, id_funcation, args);
delete [] args;

11.Java对象的创建

a.方式-NewObject

使用NewObject来创建Java对象。

jobject NewObject(jclass clazz, jmethodID methodID, ...)

需要先活的相应构造器的name,方法名设定为<init>,另外返回值的签名是Void

jmethodID GetMethodID(jclass clazz, const char *name,

const char *sig)

例子:

[cpp] view plain copy print?
  1. jclass class_date = env->FindClass("java/util/Date");
  2. jmethodID method_id = env->GetMethodID(class_date,"<init>","()V");
  3. jobject now = env->NewObject(class_date, method_id);
jclass class_date = env->FindClass("java/util/Date");
jmethodID method_id = env->GetMethodID(class_date,"<init>","()V");
jobject now = env->NewObject(class_date, method_id);

b.方式-AllocObject

12.Java字符串<---->C++字符串

a.在java中字符串String对象是Unicode(UTF-16)码,每个字符无论中文还是英文都占用两个字节。

b.可以通过JNI接口把Java中的字符串转换成C/C++中的宽字符串,Java也可以传一个UTF-8的字符串(char*) 到C/C++中。

c.反过来C++可以通过把一个宽字符串,或者一个UTF-8的字符串来创建一个Java端的对象。

13.获取Java字符串

a.取得与某个jstring对象相关的Java字符串

方法 作用
GetStringChars 取得UTF-16编码的宽字符串(char*)
GetStringUTFChars 取得UTF-8编码的字符串(char*)
[cpp] view plain copy print?
  1. const jchar *GetStringChars(jstring str, jboolean *isCopy) {
  2. return functions->GetStringChars(this,str,isCopy);
  3. }
const jchar *GetStringChars(jstring str, jboolean *isCopy) {return functions->GetStringChars(this,str,isCopy);
}

使用这两个方法,在不使用的时候,要注意使用ReleaseStringChars,或者ReleaseStringUTFChars释放拷贝的内存,或Java对象的引用。

[cpp] view plain copy print?
  1. void ReleaseStringChars(jstring str, const jchar *chars) {
  2. functions->ReleaseStringChars(this,str,chars);
  3. }
    void ReleaseStringChars(jstring str, const jchar *chars) {functions->ReleaseStringChars(this,str,chars);}

其中第一个参数表示,本地字符串的来源,第二个参数表示要释放的本地字符串

还可以使用下面的方法,这个方法可以增加返回jvm中java对象的可能性,但是还是有可能返回相应java串的拷贝。

这个方法没有相应的GetStringUTFCritical,由于Java字符串使用的是UTF-16,要转换成UTF-8编码的串本来就需要一次拷贝动作。

[cpp] view plain copy print?
  1. const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
  2. return functions->GetStringCritical(this,string,isCopy);
  3. }
  4. void ReleaseStringCritical(jstring string, const jchar *cstring) {
  5. functions->ReleaseStringCritical(this,string,cstring);
  6. }
    const jchar * GetStringCritical(jstring string, jboolean *isCopy) {return functions->GetStringCritical(this,string,isCopy);}void ReleaseStringCritical(jstring string, const jchar *cstring) {functions->ReleaseStringCritical(this,string,cstring);}

GetStringCritical与ReleaseStringCritical不能使用JNI其他的函数(诸如给jvm分配其他对象)或导致当前线程等待的任何代码。否则会导致jvm的死锁。

另外一套方法,这个方法把java的字符串直接拷贝的C/C++的字符串数组中,在呼叫之前,必须有一个C/C++分配出来的字符串。

[cpp] view plain copy print?
  1. void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
  2. functions->GetStringRegion(this,str,start,len,buf);
  3. }
  4. void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
  5. functions->GetStringUTFRegion(this,str,start,len,buf);
  6. }
    void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {functions->GetStringRegion(this,str,start,len,buf);}void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {functions->GetStringUTFRegion(this,str,start,len,buf);}

14.生成Java字符串

[cpp] view plain copy print?
  1. jstring NewString(const jchar *unicode, jsize len) {
  2. return functions->NewString(this,unicode,len);
  3. }
    jstring NewString(const jchar *unicode, jsize len) {return functions->NewString(this,unicode,len);}
[cpp] view plain copy print?
  1. jstring NewStringUTF(const char *utf) {
  2. return functions->NewStringUTF(this,utf);
  3. }
    jstring NewStringUTF(const char *utf) {return functions->NewStringUTF(this,utf);}

注意,我们可以发现NewStringUTF中,没有字符串的长度,这是因为在C/C++中字符串结尾有一个附加的标志'\0'.

获取字符串的长度的方法

[cpp] view plain copy print?
  1. jsize GetStringLength(jstring str) {
  2. return functions->GetStringLength(this,str);
  3. }
  4. jsize GetStringUTFLength(jstring str) {
  5. return functions->GetStringUTFLength(this,str);
  6. }
    jsize GetStringLength(jstring str) {return functions->GetStringLength(this,str);}jsize GetStringUTFLength(jstring str) {return functions->GetStringUTFLength(this,str);}

15.数组分为2种

a.基本类型的数组。

b.对象类型(Object[])的数组。

有一个通用于两种不同数组的的函数:

[cpp] view plain copy print?
  1. jsize GetArrayLength(jarray array) {
  2. return functions->GetArrayLength(this,array);
  3. }
    jsize GetArrayLength(jarray array) {return functions->GetArrayLength(this,array);}

16.处理基本类型数组

跟处理字符串相似

Get<Type>ArrayElements,可以把Java基本类型的数组转换成C/C++中的数组,可以拷贝一份传本地代码,也可以把指向Java中的指针直接传回本地代码。

需要用

Release<Type>ArrayElements

[cpp] view plain copy print?
  1. void ReleaseIntArrayElements(jintArray array,
  2. jint *elems,
  3. jint mode) {
  4. functions->ReleaseIntArrayElements(this,array,elems,mode);
  5. }
    void ReleaseIntArrayElements(jintArray array,jint *elems,jint mode) {functions->ReleaseIntArrayElements(this,array,elems,mode);}

mode:

0:对Java数组进行更新,并释放C/C++的数组。

JNI_COMMIT: 对Java数组进行更新但不释放C/C++数组。

JNI_ABORT:对Java数组不进行更新,并释放C/C++数组。

相似GetStringUTFCritical的函数:为了直接传回指向Java数组的指针而加入的函数。

[cpp] view plain copy print?
  1. void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
  2. return functions->GetPrimitiveArrayCritical(this,array,isCopy);
  3. }
  4. void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {
  5. functions->ReleasePrimitiveArrayCritical(this,array,carray,mode);
  6. }
    void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {return functions->GetPrimitiveArrayCritical(this,array,isCopy);}void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {functions->ReleasePrimitiveArrayCritical(this,array,carray,mode);}

Get<Type>ArrayRegion 相似于GetStringRegion的函数:没有Release方法,因为我们是拷贝

[cpp] view plain copy print?
  1. void GetIntArrayRegion(jintArray array,
  2. jsize start, jsize len, jint *buf) {
  3. functions->GetIntArrayRegion(this,array,start,len,buf);
  4. }
    void GetIntArrayRegion(jintArray array,jsize start, jsize len, jint *buf) {functions->GetIntArrayRegion(this,array,start,len,buf);}

Set<Type>ArrayRegion 可以把指定范围内的Java数组元素用C++中的元素赋值。

[cpp] view plain copy print?
  1. void SetIntArrayRegion(jintArray array, jsize start, jsize len,
  2. const jint *buf) {
  3. functions->SetIntArrayRegion(this,array,start,len,buf);
  4. }
    void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint *buf) {functions->SetIntArrayRegion(this,array,start,len,buf);}

创建一个基本类型的Java数组

<Type>Array New<Type>Array(jsize size),指定长度后返回相应Java基本类型的数组。

17.处理Object类型数组

JNI中没有把Java对象类型的数组转换成C++中的jobject[]的函数。而是直接通过Get/SetObjectArrayElement来对Java的Object数组进行操作。

[cpp] view plain copy print?
  1. jobject GetObjectArrayElement(jobjectArray array, jsize index) {
  2. return functions->GetObjectArrayElement(this,array,index);
  3. }
  4. void SetObjectArrayElement(jobjectArray array, jsize index,
  5. jobject val) {
  6. functions->SetObjectArrayElement(this,array,index,val);
  7. }
    jobject GetObjectArrayElement(jobjectArray array, jsize index) {return functions->GetObjectArrayElement(this,array,index);}void SetObjectArrayElement(jobjectArray array, jsize index,jobject val) {functions->SetObjectArrayElement(this,array,index,val);}

使用上述方式不需要释放资源。

可以根据数组长度和初始值来创建某个类的数组

[cpp] view plain copy print?
  1. jobjectArray NewObjectArray(jsize len, jclass clazz,
  2. jobject init) {
  3. return functions->NewObjectArray(this,len,clazz,init);
  4. }
    jobjectArray NewObjectArray(jsize len, jclass clazz,jobject init) {return functions->NewObjectArray(this,len,clazz,init);}

18.java对象在JNI中的引用

在jvm中创建的对象被传到本地的C/C++代码的时候,会产生引用。根据jvm的垃圾回收机制,只要引用存在,就不会触发该引用指向对象的被回收。

这些引用分为三种

全局引用:Global Reference

局部引用:Local Reference

弱全局引用:Weak Global Reference

局部引用:是最常见的引用,局部引用只在native函数中有效。局部引用的存在会阻止其指向对象的回收。

全局引用:

可以跨越多个线程

在多个navtive方法中有效、

全局引用存在期间会阻止其引用java对象在jvm的回收。

全局引用的创建不是JNI自动创建的。

全局引用的创建要显示的调用NewGlobalRef函数,而释放需要调用ReleaseGlobalRef

弱全局引用:

与全局引用相似,创建和释放都需要由编程人员来进行。

多个线程,多个native方法中有效。

区别:这个引用不会阻止jvm回收其指向的引用。

NewWeakGlobalRef与ReleaseWeakGlobalRef来创建和释放引用。

19.IsSameObject在弱全局引用中有一个特别的功能。

把NULL传给要判断的object,来判断弱全局引用指向的java对象是否被回收。

20.缓存jfieldID,jmethodID.

a.通过方法名+签名来查询jfieldID,jmethod开销是非常大的。

b.缓存方式:

1.在使用的时候缓存。(Caching at the Point of Use)

使用static类型的局部变量来保存已经查询过的ID,这样就不会在每次调用的时候查询,而是只查询一次。

2.在java类初始化的时候缓存。(Caching at Class's inititalizer)

这种加载方式在jvm类的加载和重新加载都会重新呼叫该native方法重新计算ID

[java] view plain copy print?
  1. public class TestNative
  2. {
  3. static {
  4. initNativeIDs();
  5. }
  6. static natvie void initNativeIDs();
  7. int propInt = 0;
  8. }
public class TestNative
{static {initNativeIDs();}static natvie void initNativeIDs();int propInt = 0;
}
[cpp] view plain copy print?
  1. JNIEXPORT void JNICALL    Java_TestNative_initNativeIDs(JNIEnv *env, jobject object)
  2. {
  3. ......
  4. g_propInt_id = GetFieldID(clazz,  "propInt", "I" );
  5. }

学习JNI一些基础知识相关推荐

  1. JNI学习开始篇 基础知识 数据映射及学习资料收集

    JNI学习开始篇 基础知识 数据映射及学习资料收集 JNI介绍 JNI(Java Native Interface) ,Java本地接口. 用Java去调用其他语言编写的程序,比如C或C++. JNI ...

  2. OpenCV与图像处理学习一——图像基础知识、读入、显示、保存图像、灰度转化、通道分离与合并

    OpenCV与图像处理学习一--图像基础知识.读入.显示.保存图像.灰度转化.通道分离与合并 一.图像基础知识 1.1 数字图像的概念 1.2 数字图像的应用 1.3 OpenCV介绍 二.图像属性 ...

  3. php基础教学笔记,php学习笔记:基础知识

    php学习笔记:基础知识 2.每行结尾不允许有多余的空格 3.确保文件的命名和调用大小写一致,是由于类Unix系统上面,对大小写是敏感的 4.方法名只允许由字母组成,下划线是不允许的,首字母要小写,其 ...

  4. 计算机网络基础心得体会结尾,学习《计算机网络基础知识》心得体会

    学习<计算机网络基础知识>心得体会 ... 如今已经是信息时代,作为主流信息工具的网络越来越重 要,网络是信息的载体,是人们传递感情的工具.随着信息社会 的不断发展,网络的应用将会更加广泛 ...

  5. 计算机学生要学的基础知识,中小学生应注重学习计算机的基础知识

    "知识爆炸"和"知识老化"这两大问题,不断困扰着现代教育,人们解决这一问题的良方之一,就是加强学生对基础知识的学习.近年来在中国兴起的中小学生学习计算机热,也同 ...

  6. 【学习笔记--FMCW基础知识】

    学习笔记--FMCW基础知识 前言 mmWave测距原理 mmWave区分多个物体 mmWave的距离分辨率(Range Solution) mmWave的最大测量距离 前言 由于工作原因需要了解TI ...

  7. 使用Vue3学习Vue的基础知识

    创建 Vue 应用 vue的安装有多种方式,本文只讨论基础知识,其他安装方式请自行查阅官网 https://v3.cn.vuejs.org/guide/installation.html 本文使用CD ...

  8. Day 01嵌入式学习之Linux基础知识和命令操作

    学习嵌入式开发的随堂笔记 Day 01嵌入式学习之linux基础知识和命令操作 1.英文: read:读,r字母 write:写,w字母 execute:执行,运行,x字母 directory:目录, ...

  9. kpu 处理器_深度学习及 KPU 基础知识

    深度学习及 KPU 基础知识 1. 阅读完本章文档可以了解什么? 了解深度学习一些基础内容 了解 K210 内部 KPU 的特性 了解 KPU 使用过程中可能会遇到的问题,以及问题的解决方法 2. 概 ...

最新文章

  1. Java项目:在线蛋糕商城系统(java+jsp+jdbc+mysql)
  2. 波士顿动力机器狗量产版首次亮相:先造100台,能当警犬能工地巡逻
  3. oracle 实现HA,oracle RAC的客户端HA配置
  4. TensorFlow学习笔记(一)安装、配置、基本用法
  5. linux gcc march arch,Gcc的spec中arch什么的指定
  6. 登上热搜!这可能是中国最穷的211大学
  7. 单行 - JAVA 条件表达式
  8. 使用Python 正则匹配两个特定字符之间的字符方法
  9. 测试智慧城市项目API接口
  10. TCP / IP攻击:ARP缓存中毒的基本原理、TCP序列号预测和TCP重置攻击
  11. 有人问我:Linux下命令行里 password:的时候 用键盘密码打不了
  12. GDAL源码剖析(十)之编写自己的扩展格式
  13. linux部署java命令
  14. 1980-2010的87个国家/地区的一些经济和金融发展指标简单归纳和解释以及如何套动态面板公式计算
  15. 《买土豆的故事》——经典职场故事
  16. 按键精灵脚本-windows桌面自动化操作
  17. Emlog html5视频播放器插件
  18. 用深度学习做了下中国股市预测,结果是...
  19. JavaScript捕获同时多个按键-非组合键
  20. Blender+PS三维辅助CG场景概念设计学习教程

热门文章

  1. 卢京潮自动控制原理ppt_视觉定位系统在贴片机中的使用与原理作用
  2. python调用gitlab api自动合并分支_Python3使用 GitLab API 进行批量合并分支
  3. P4491 [HAOI2018]染色
  4. Investigating SQL Server 2008 Wait Events with XEVENTS
  5. EMQ学习 ---集群
  6. Java maven的 pom.xml配置文件中使用全局变量配置版本号
  7. 安卓图表引擎AChartEngine(一) - 简介
  8. Lync Server 2010迁移至Lync Server 2013部署系列21:Lync 2013边缘第二台服务器配置
  9. scau实验题 8596 Longest Ordered Subsequence
  10. 我的博客博客之路....