1.学习JNI的含义、功能、最简单的Java调用C/C++代码的步骤,并按最简单的步骤编写在Java程序中调用本地代码的实例。内容包括:javah工具的用法、按照C/C++头文件来编写C/C++源文件、将C/C++源文件编译成动态连接库(DLL)、在Java程序中引入动态连接库等知识。
编写实例:在c++中输出“HelloWorld”,在java程序中调用c++的输出内容。成功在java 控制台输出HelloWorld。
2.在被调用的C/C++函数中如何访问Java程序中的类,并编写应用实例。内容包括:在javah 工具生成的C/C++函数声明中的JNIEnv类型参数和jobject类型参数的介绍、Java类型在C/C++中的映射关系、jclass类型的含义及取得、访问Java类中的属性与方法,以及使用javap 工具获得属性和方法的签名。
为了能够在c/c++中使用java类,JNI.h头文件定义了jclass类型来表示java中的class类,在JNI中取得jclass类的方法有:
Jclass FindClass(const char* className); //FindClass方法会在classPath系统环境变量下寻类,需要传入完整的类名,包与包之间用“/”分隔
3.在被调用的C/C++函数中如何取得/设定Java属性值、如何调用Java类的方法和调用Java 类的父类的方法,并编写应用实例。
为了在c/c++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethodID类型分别代表java端的属性和方法。
可以通过JNIEnv中的GetFieldID / GetMethodID或者GetStaticFieldID/GetStaticMehtID来获取相应的jfieldID和jmethodID
取java属性:
Get<TYPE> Field();
GetStatic<TYPE> Field();
设置java属性:
Set<TYPE> Field();
SetStatic<TYPE> Field();
JNI提供
Call<TYPE> Method();
CallStatic<TYPE> Method();
CallNonvirtual<TYPE> Method()方法来进行对java方法的调用
想要调用一个对象的父类方法,而不是子类方法,就可以用
CallNonvirtual<TYPE> Method()方法来实现。
使用此方法需要(1) 获取父类及要调用的父类方法的jmethodID;
java设置环境变量的方法代码(2)将jmethodID传入到函数中就能通过子类对象呼叫被重载的父类的方法。
4.如何在本地代码中生成和操作Java的对象和字符串,并编写应用实例。内容包括:在C/C++本地代码中创建Java对象、在C/C++本地代码中访问Java的String对象、在C/C++本地代码中创建Java的String对象。
在c/c++本地代码中创建java对象,用到的函数式NewObject()函数
在c/c++本地代码中访问java中的String字符串对象:
在java中,使用的字符串String对象时unicode码,即一个字符串占两个字节,java通过JNI 接口可以将ja
va中的字符串转换到c/c++中的宽字符串中,或者传回一个utf-8的字符串到c/c++中。
访问java字符串函数:
GetStringchars() 这个函数会开辟一个新的内存,然后把java中的String对象拷贝到这个内存中,然后返回指向这个内存地址的指针。
使用这个函数取得字符串后,在不使用时,要用ReleaseStringchars/ReleaseStringUTFchars 来释放拷贝的内存或者释放对java的String对象的引用。
创建java的String字符串对象:
NewString()和NewStringUTF()
取得字符串长度:GetStringLength()和GetStringUTFLength()
5.本地c/c++中处理java中的数组。
数组分为两种:基本类型数组和对象类型Object[] 的数组
基本类型数组:
把java基本类型的数组转换成c++中的数组,方法是:
Get<TYPE> ArrayElements(<TYPE> Array arr,jboolean * iscopied);
释放数组的方法:
Release<TYPE> ArrayElements(<TYPE> Array arr, <TYPE>* array, jint mode);
Mode可以取下边的值:
0 -----> 对java的数组进行更新并释放c/c++中的数组
JNI_COMMIT -------> 对java的数组更新但是不会释放c/c++的数组
JNI_ABORT -------> 对java中的数组不进行更新,释放c/c++的数组
获取数组的长度:GetArrayLength(jarray array);
取得java中数组的元素:
Get<TYPE> ArrayRegion (<TYPE> Array arr, jsize startLen, jsize endLen, <TYPE> * buffer); 这个函数
会在c/c++中预先开辟一段内存,然后把java基本类型的数组拷贝到这段内存中。设置java中数组的元素:
Set<TYPE> ArrayRegion(<TYPE> Array arr, jsize startLen, jsize endLen, <TYPE> * buffer); 把java基本类型的数组中的指定范围的元素用c/c++的数组中的元素来赋值。
创建java基本类型的数组:
New<TYPE> Array(jsize size);
指定一个长度然后返回相应java基本类型的数组。
对象类型数组:
JNI没有提供直接把java中的对象类型的数组直接传到c++中的函数,但是可以通过
Get/SetObjectArrayElement 这个函数来对java的对象数组进行操作,这个函数没有开辟内存空间,所以不用释放。
实例:1. 在java中定义一个数组,在c++中使用JNI的语法,在java控制台输出数组的每
个元素。
2.使用sort()函数对Java中定义的数组进行排序并更新到java代码中。
使用sort() 函数语法:
引入头文件#include<algorithm>
std:: sort(获取到的数组元素,获取到的数组元素+数组的长度);
对数组进行排序完后,释放数组时mode属性设置为0 ,表示更新并释放数组。
6:JNI中的全局引用/局部引用/弱全局引用
从java虚拟机创建的对象传到本地c/c++代码中时会产生引用,根据java的垃圾回收机制,只要有引用存在就不会触发该引用指向的java对象的垃圾回收。
全局引用:Global Reference
可以跨越当前线程,在多个native函数中有效,不过该引用需要手动释放,全局引用的创建不是由JNI自动创建的,而是由NewGlobalRef函数创建,释放由ReleaseGlobalRef函数进行释放。
局部引用:Local Reference
最常用的引用类型,只在native函数中有效,所有局部引用都会在函数返回时自动释放,也可以使用DeleteLocalRef函数手动释放该引用。
关于引用的一些函数:
jobject NewGlobalRef(jobject obj ); 创建全局引用
jobject NewLocalRef(jobject obj ); 创建局部引用
jobject NewWeakGlobalRef(jobject obj ); 创建弱全局引用
void DeleteGlobalRef (jobject obj); 删除全局引用
void DeleteLocalRef (jobject obj); 删除局部引用
void DeleteWeakGlobalRef (jobject obj); 删除弱全局引用
jboolean IsSameObject(jobject obj1, jobject obj2);
这个函数是用来比较obj1的引用和obj2的引用是否指向同一个java对象,当其中一个参数为NULL时,就可以根据返回值来判断弱全局引用所指的java对象是否被回收。
使用JNI的弊端:
1.使用了JNI 后,那么java 项目将不能跨平台,如果要移植到别的平台上,那么native 代码必须重新编写。
2.Java是强类型语言,c/c++不是,必须在写JNI时更加小心。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论