JNI函数操作实战

在上几篇文章中,我们学习了jni的相关基础,这次我们就通过相关的jni函数操作来加强练习。

 一、Native函数返回int数据
Java层定义的native方法。
public class HelloJni {
	//求和
	public native int getJniInt(int x, int y);
}
.c文件中的native方法实现。
JNIEXPORT jint JNICALL Java_com_dsw_hellojni_HelloJni_getJniInt
  (JNIEnv *env, jobject obj, jint x, jint y){
	return x + y;
}
针对基本数据类型,在java层和native层可以直接进行相互转换,无需进行过多的数据类型转换。
二、Native层返回String类型数据。
Java层定义的native方法。
public class HelloJni {
	//String字符串倒序输出
	public native String getJniString(String str);
}
native方法的实现:
JNIEXPORT jstring JNICALL Java_com_dsw_hellojni_HelloJni_getJniString
  (JNIEnv *env, jobject obj, jstring str){
	char *ch = (*env)->GetStringUTFChars(env,str,NULL);
	char *endch = ch;
	while(*endch){
		endch++;
	}
	endch--;
	while(endch >ch){
		char t = *ch;
		*ch = *endch;
		*endch = t;
		ch++;
		endch--;
	}


	jstring resultStr = (*env)->NewStringUTF(env,ch);
	return resultStr;
}

由于Java层和native层的String对象是无法直接进行交互的,所以我们需要进行数据类型的转换。在上面我们通过GetStringUTF方法进行转换成字符指针进行处理。这也是在jni中处理字符串的核心思路,转换成字符指针进行处理。下面是访问String的一些方法:
GetStringUTFChars将jstring转换成为UTF-8格式的char*
GetStringChars将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars释放指向UTF-8格式的char*的指针
ReleaseStringChars释放指向Unicode格式的char*的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取 UTF-8格式的char*的长度 
GetStringLength获取Unicode格式的char*的长度


三、Native层返回一维数组
Java层定义的native函数。
public class HelloJni {
	public native int[] getJniArrayInt();
}
native方法的实现:
JNIEXPORT jintArray JNICALL Java_com_dsw_hellojni_HelloJni_getJniArrayInt
  (JNIEnv *env, jobject obj){
	jintArray intArray = (*env)->NewIntArray(env,20);
	jint result[20];
	jint i = 1;
	for(i = 0; i<10;i++){
		result[i] = i;
	}
	(*env)->SetIntArrayRegion(env,intArray,0,10,result);
	return intArray;
}
这里注意,
1)添加参数在(JNIEnv* env,jobject thiz) 后面添加 如:(JNIEnv* env,jobject thiz,jintArray nums )
2)获取数组的长度 jsize len =(*jniEnv)->GetArrayLength(jniEnv, nums);
3)新建数组 jintArray array =(*jniEnv)-> NewIntArray(jniEnv, len); 如果是新建别的数组,NewIntArray 要做相对应的改变
4)获取 数组里面的元素:

(*env)->GetIntArrayElements(env,nums, isCopy) , 返回 所有数据。If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy ismade; if no copy is made, it is set to JNI_FALSE.
 (*env)->GetIntArrayRegion(env,array,start,len,buffer), 从start开始复制长度为len 的数据到buffer中

5)设置 数组里面的元素
(*env)->SetIntArrayRegion(env,array,start,len,buffer) , 从start开始复制长度为len 的数据 buffer到 array 中


四、Native层返回二维数组
Java层native方法定义:
public class HelloJni {
	public native int[] getJniArrayInt();
}
native方法的实现:
JNIEXPORT jobjectArray JNICALL Java_com_dsw_hellojni_HelloJni_getJniTwoArrayString
  (JNIEnv *env, jobject obj){
	jint dimion = 10;
	jclass intArrayClass = env->FindClass("[I"); //获得一维数组 的类引用,即jintArray类型
	//构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为dimion
	jobjectArray obejctIntArray  =  env->NewObjectArray(dimion ,intArrayClass , NULL);
	//构建dimion个一维数组,并且将其引用赋值给obejctIntArray对象数组
	for( int i = 0 ; i< dimion  ; i++ )
	{
		//构建jint型一维数组
		jintArray intArray = env->NewIntArray(dimion);
		jint temp[10]  ;  //初始化一个容器,用于装一行的值
		for( int j = 0 ; j < dimion ; j++)
		{
			temp[j] = i + j  ; //赋值
		}


		//将temp中的值赋值给intArray数组
		env->SetIntArrayRegion(intArray, 0 , dimion ,temp);
		//给object对象数组赋值,即保持对jint一维数组的引用
		env->SetObjectArrayElement(obejctIntArray , i ,intArray);
		env->DeleteLocalRef(intArray);  //删除局部引用
	}
	return   obejctIntArray; //返回该对象数组
}

总结:
1.获取指定对象的类定义(jclass) 
有两种途径来获取对象的类定义:第一种是在已知类名的情况下使用FindClass来查找对应的类。但是要注意类名并不同于平时写的Java代码,例如要得到类jni.test.Demo的定义必须调用如下代码: 

jclass cls = (*env)->FindClass(env, "jni/test/Demo"); //把点号换成斜杠
    
然后通过对象直接得到其所对应的类定义: 

    jclass cls = (*env)-> GetObjectClass(env, obj);
    //其中obj是要引用的对象,类型是jobject
    
2.读取要调用方法的定义(jmethodID) 
我们先来看看JNI中获取方法定义的函数:
    jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name, 
    const char *sig);
    jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char 
    *name, const char *sig);  
这两个函数的区别在于GetStaticMethodID是用来获取静态方法的定义,GetMethodID则是获取非静态的方法定义。这两个函数都需要提供四个参数:env就是初始化虚拟机得到的JNI环境;第二个参数class是对象的类定义,也就是第一步得到的obj;第三个参数是方法名称;最重要的是第四个参数,这个参数是方法的定义。因为我们知道Java中允许方法的多态,仅仅是通过方法名并没有办法定位到一个具体的方法,因此需要第四个参数来指定方法的具体定义。但是怎么利用一个字符串来表示方法的具体定义呢?JDK中已经准备好一个反编译工具javap,通过这个工具就可以得到类中每个属性、方法的定义。
3.调用方法 
为了调用对象的某个方法,可以使用函数CallMethod或者CallStaticMethod(访问类的静态方法),根据不同的返回类型而定。这些方法都是使用可变参数的定义,如果访问某个方法需要参数时,只需要把所有参数按照顺序填写到方法中就可以。
4.访问类属性

访问类的属性与访问类的方法大体上是一致的,只不过是把方法变成属性而已。


更多文章参考:http://blog.csdn.net/qinjuning/article/details/7607214

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值