JNI语言基本知识
jni简介
jni是java native interface的缩写,它提供了若干的api实现了java和其他语言的通信(主要是c&c++)。从java1.1开始,jni标准成为java平台的一部分,它允许java代码和其他语言写的代码进行交互。jni一开始是为了本地已编译语言,尤其是c和c++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。jni标准至少要保证本地代码能工作在任何java 虚拟机环境。
一、本地方法的参数
如何本地方法声明为static,那么生成的头文件中的本地方法形式如下:
jniexport void jnicall java_com_tao_test_nativetest_sayhello (jnienv * , jclass);
这两个参数的意思是什么:jnienv类型实际上代表了java环境。通过这个jnienv*指针,就可以对java端的代码进行操作。例如,创建java类的对象,调用java对象的方法,获取java对象的属性等等。jnienv的指针会被jni传入到本地方法的实现函数中来对java端的代码进行操作。而jclass,则代表调用这个静态方法类的class对象,即该class类的字节码。
如何本地方法没有声明为static,那么生成的头文件中的本地方法形式如下:
jniexport void jnicall java_com_tao_test_nativetest_sayhello (jnienv * , jobject);
jobject类型相当于java中的object类型,它代表调用这个本地方法的对象,实际上准确的说,,保持了一个对 调用这个方法的的对象的引用。比如说,如果是new nativetest().sayhello()调用这个方法,那么这个引用指向了这个new nativetest()对象。
jnienv类中有许多函数可以用:
newobject 创建一个对象
newstring 创建一个string对象
new<type>array 创建某个类型的数组
get/set<type>field 获取或设置某个成员变量的属性
get/setstatic<type>field 获取或设置某个成静态员变量的属性
call<type>method/callstatic<type>method 调用某个java对象的方法/或静态方法
等等许多函数
二、数值参数
用java代码调用c\c++代码时候,肯定会有数值的传递。两者属于不同的编程语言,在数据类型上有很多差别,应该要知道他们彼此之间的对应类型。例如,尽管c拥有int和long的数据类型,但是他们的实现却是取决于平台的。在一些平台上,int类型是16位的,而在另外一些平台上市32位的整数。基于这个原因,java本地接口定义了jint,jlong等等。
java类型和c/c++数据类型的对应关系,可以看到,这些新定义的类型名称和java类型名称具有一致性,只是在前面加了个j,如int对应jint,long对应jlong。
我们看看jni.h和jni_md.h头文件,可以更直观的了解:
typedef unsigned char jboolean; typedef unsigned short jchar; typedef short jshort; typedef float jfloat; typedef double jdouble; typedef long jint; typedef __int64 jlong; typedef signed char jbyte;
可以看到,例如jint代表的是和java类型int一样的类型,但是并不是c/c++中int。从定义可以看到,java中的int,也就是jni中的jint,对应的是c/c++中的long类型。
所以如果要在本地方法中要定义一个jint类型的数据,规范的写法应该是 jint i=10l;
在 比如jchar代表的是java类型的char类型,实际上在c/c++中却是unsigned short类型 ,而在c/c++中有这样的定义:typedef unsigned short wchar_t。所以jchar就是相当于c/c++中的宽字符,也就是说java中的char 相当于c/c++中的宽字符。所以如果要在本地方法中要定义一个jchar类型的数据,规范的写法应该是jchar c=l'c';
实际上,所以带j的类型,都是代表java中的类型,它与c/c++中的类型是不一样的,所以在内部都要转换,我们在使用的时候也需要小心。可以看后面关于jni中对字符串的操作。
三。java对象在c\c++代码中的形式
查看jni.h头文件,可以看到下面的内容
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 {};
其实这些加了_j首字母的类,都是集成于_jobject,这也是为了照顾我们java中的,object类是一切类的基类。
这些类,对应的就是java中的类,只不过,在c/c++中换了中形式而已。
四、jclass类和如何取得jclass对象
在java中,class类型代表一个类编译的字节码,即这个类,里面包含了这个类的所有信息。在jni中,同样定义了这样一个类,那就是jclass。了解反射的人都知道class类是如何重要,可以通过反射获得java类的信息和访问里面的方法和成员变量。所以在jni中,也有这样一个jclass类,来代表class类。
jnienv有几个方法可以取得jclass对象:
jclass findclass(const char *name) { return functions->findclass(this, name); }
findclass会在系统classpath下寻找类,传入完整的类型,注意包的间隔使用 / ,而不是. 比如:
jclass cls_string=env->findclass("java/lang/string"); jclass getobjectclass(jobject obj) { return functions->getobjectclass(this,obj); } jclass getsuperclass(jclass sub) { return functions->getsuperclass(this, sub); }
得到java类的class对象,即jclass,那么就可以用和反射差不多的形式,来得到java类中的成员变量和方法等等,虽然方式和class不一样,不过大抵的形式相当。
总结
以上所述是小编给大家介绍的jni语言基本知识,希望对大家有所帮助