上篇文章,我们介绍了makefile的一些基本语法,本次我们接着学习jni的函数结构和数据类型方面的知识。
一、Jni函数结构
我们来看个jni函数实例:
(1)、JNIEXPORT:jni本地方法的标识,在所有本地接口实现的方法前面都有一个“JNIEXPORT”的标识。
(2)、jstring:函数的返回值类型,我们本地定义的函数返回值类型是String,所以此时转到jni中就是jstring。此外还有void,jint等类型。
(3)JNICALL:一种标识,可以理解为jni调用后面的方法。
(4)Java_com_dsw_hellojni_HelloJni_getHelloJni:本地方法通过javah编译生成的对应jni方法名。结构是
Java_包名_类名_对应的native方法名。
(5)、JNIEnv:JavaVM在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;JNIEnv有两个作用:调用Java函数、操作Java传入jni的对象。
(6)jobject:刚才在Test类的main方法中有这样一段代码:
Test t=new Test(); t.firstTest();
这个jobject需要两种情况分析。上段代码中firstTest方法是一个非静态方法,在Java中要想调用它必须先实例化对象,然后再用对象调用它,那这个时候jobject就可以看做Java类的一个实例化对象,也就是obj就是t。如果firstTest是一个静态方法,那么在Java中,它不是属于一个对象的,而是属于一个类的,Java中用Test.firstTest()这样的方式来调用,这个时候jobject就可以看做是java类的本身,也就是obj就是Test.class。
二、jni数据类型
基本数据类型:
引用数据类型:
Java类型和本地类型交互场景:
1)java方法里面将参数传入本地方法;
2)在本地方法里面创建java对象;
3)在本地方法里面return结果给java程序。
根据交互的数据类型分为如下两种情况:
(1)、Java基本数据类型
像booleans、integers、floats等从Java程序中传到本地方法中的原始类型可以直接使用,参照上面列出来的。
(2)、Java引用类型
Java对象做为引用被传递到本地方法中,所有这些Java对象的引用都有一个共同的父类型jobject(相当于java中的Object类是所有类的父类一样)。这里就需要利用JNIEnv对象所提供的方法来进行数据类型的转换。
三、描述符
(1)、类描述符是完整的类名称(包名+类名)组成,同时由/线组成,比如:
java/lang/String。
(2)、数组描述符,由[ + 数组类型域描述符组成。例如:
int[] 描述为:[I
四、域描述符
(1)、基本类型域描述符
Jni的所有操作,其实就是操作方法或者是操作属性两种。操作方法时需要根据方法的ID(jmethodID)来操作,可以理解为jmethodID标识了这个方法,也就是通过这个jmethodID可以找到你要找的方法。同理操作属性时也要根据该属性的ID(jfieldID )来操作。上面那段代码里我们要改变 变量message的值,所以要先获取该变量的jfieldID 。获取变量的jfieldID 方法是GetFieldID。GetFieldID需要3个参数。第一个是上一步获取的Jclass,第二个参数是Java中的变量名,最后一个参数是变量签名(int 的变量签名是”I“)。
(2)、引用类型域描述符
一般引用类型则为 L + 该类型类描述符 + ;
String类型的域描述符为 Ljava/lang/String;
对于数组,其为 : [ + 其类型的域描述符 + ;
int[ ] 其描述符为[I
多维数组则是 n个[ +该类型的域描述符 , N代表的是几维数组。例如:
int [ ][ ] 其描述符为[[I
(3)方法描述符:形式如下:
(各个函数的参数类型的域描述符组合)返回值类型的域描述符。例如:
一、Jni函数结构
我们来看个jni函数实例:
JNIEXPORT jstring JNICALL Java_com_dsw_hellojni_HelloJni_getHelloJni
(JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env,"HelloJni");
}
下面我们就针对这个方法进行解析:(1)、JNIEXPORT:jni本地方法的标识,在所有本地接口实现的方法前面都有一个“JNIEXPORT”的标识。
(2)、jstring:函数的返回值类型,我们本地定义的函数返回值类型是String,所以此时转到jni中就是jstring。此外还有void,jint等类型。
(3)JNICALL:一种标识,可以理解为jni调用后面的方法。
(4)Java_com_dsw_hellojni_HelloJni_getHelloJni:本地方法通过javah编译生成的对应jni方法名。结构是
Java_包名_类名_对应的native方法名。
(5)、JNIEnv:JavaVM在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;JNIEnv有两个作用:调用Java函数、操作Java传入jni的对象。
(6)jobject:刚才在Test类的main方法中有这样一段代码:
Test t=new Test(); t.firstTest();
这个jobject需要两种情况分析。上段代码中firstTest方法是一个非静态方法,在Java中要想调用它必须先实例化对象,然后再用对象调用它,那这个时候jobject就可以看做Java类的一个实例化对象,也就是obj就是t。如果firstTest是一个静态方法,那么在Java中,它不是属于一个对象的,而是属于一个类的,Java中用Test.firstTest()这样的方式来调用,这个时候jobject就可以看做是java类的本身,也就是obj就是Test.class。
二、jni数据类型
基本数据类型:
引用数据类型:
Java类型和本地类型交互场景:
1)java方法里面将参数传入本地方法;
2)在本地方法里面创建java对象;
3)在本地方法里面return结果给java程序。
根据交互的数据类型分为如下两种情况:
(1)、Java基本数据类型
像booleans、integers、floats等从Java程序中传到本地方法中的原始类型可以直接使用,参照上面列出来的。
(2)、Java引用类型
Java对象做为引用被传递到本地方法中,所有这些Java对象的引用都有一个共同的父类型jobject(相当于java中的Object类是所有类的父类一样)。这里就需要利用JNIEnv对象所提供的方法来进行数据类型的转换。
三、描述符
(1)、类描述符是完整的类名称(包名+类名)组成,同时由/线组成,比如:
java/lang/String。
(2)、数组描述符,由[ + 数组类型域描述符组成。例如:
int[] 描述为:[I
四、域描述符
(1)、基本类型域描述符
Jni的所有操作,其实就是操作方法或者是操作属性两种。操作方法时需要根据方法的ID(jmethodID)来操作,可以理解为jmethodID标识了这个方法,也就是通过这个jmethodID可以找到你要找的方法。同理操作属性时也要根据该属性的ID(jfieldID )来操作。上面那段代码里我们要改变 变量message的值,所以要先获取该变量的jfieldID 。获取变量的jfieldID 方法是GetFieldID。GetFieldID需要3个参数。第一个是上一步获取的Jclass,第二个参数是Java中的变量名,最后一个参数是变量签名(int 的变量签名是”I“)。
(2)、引用类型域描述符
一般引用类型则为 L + 该类型类描述符 + ;
String类型的域描述符为 Ljava/lang/String;
对于数组,其为 : [ + 其类型的域描述符 + ;
int[ ] 其描述符为[I
多维数组则是 n个[ +该类型的域描述符 , N代表的是几维数组。例如:
int [ ][ ] 其描述符为[[I
(3)方法描述符:形式如下:
(各个函数的参数类型的域描述符组合)返回值类型的域描述符。例如:
int f (int i, Object object) 对应(ILjava/lang/Object;)I
上面就是介绍的类型和域限定符等基础知识。