• Java中JNI的使用详解第五篇:C/C++中操作Java中的数组 2013-12-29 14:29 2941人阅读 评论(0) 收藏


    在Java中数组分为两种:

    1.基本类型数组

    2.对象类型(Object[])的数组(数组中存放的是指向Java对象中的引用)

    一个能通用于两种不同类型数组的函数:

    GetArrayLength(jarray array);


    首先来看一下怎么处理基本类型的数组:

    (1) Get<Type>ArrayElements(<Type>Array arr , jboolean* isCopide);

    这类函数可以把Java基本类型的数组转换到C/C++中的数组,有两种处理方式,一种是拷贝一份传回本地代码,另一个是把指向Java数组的指针直接传回到本地代码中,处理完本地化的数组后,通过Release<Type>ArrayElements来释放数组


    (2) Release<Type>ArrayElements(<Type>Array arr , <Type>* array , jint mode)

    用这个函数可以选择将如何处理Java跟C++的数组,是提交,还是撤销等,内存释放还是不释放等

    mode可以取下面的值:

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

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

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


    (3) GetPrimittiveArrayCritical(jarray arr , jboolean* isCopied);

    (4) ReleasePrimitiveArrayCritical(jarray arr , void* array , jint mode);

    也是JDK1.2出来的,为了增加直接传回指向Java数组的指针而加入的函数,同样的也会有同GetStringCritical的死锁的问题


    (5) Get<Type>ArrayRegion(<Type>Array arr , jsize start , jsize len , <Type>* buffer);

    在C/C++预先开辟一段内存,然后把Java基本类型的数组拷贝到这段内存中,这个方法和之前拷贝字符串的GetStringRegion方法的原理是类似的


    (6) Set<Type>ArrayRegion(<Type>Array arr , jsize start , jsize len , const <Type>* buffer);

    把Java基本类型的数组中的指定范围的元素用C/C++的数组中的元素来赋值


    (7) <Type>Array New<Type>Array(jsize sz)

    指定一个长度然后返回相应的Java基本类型的数组


    在来看一下怎么处理对象型数组

    JNI没有提供直接把Java的对象类型数组(Object[])直接转到C++中的Object[]数组的函数,而是直接通过Get/SetObjectArrayElement这样的函数来对Java的Object[]数组进行操作由于去的对象数组没有进行拷贝,所以不需要释放任何资源

    NewObjectArray可以通过指定长度跟初始值来创建某个类的数组


    下面来看一下例子:操作两种类型的数组

    Java中的代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. package com.jni.demo;  
    2.   
    3. public class JNIDemo {  
    4.     //定义一个int型数组  
    5.     int[] arrays = {4,3,12,56,1,23,45,67};  
    6.     //定义Father对象数组  
    7.     Father[] objArrays = {new Father(),new Father(),new Father()};   
    8.     //定义一个本地方法  
    9.     public native void callCppFunction();  
    10.     public static void main(String[] args)throws Exception{  
    11.         //调用动态链接库  
    12.         System.loadLibrary("JNIDemo");  
    13.         JNIDemo jniDemo = new JNIDemo();  
    14.         jniDemo.callCppFunction();  
    15.           
    16.     }  
    17. }  
    18. </span>  

    C++中的代码:

    1. #include<iostream>  
    2. #include"com_jni_demo_JNIDemo.h"  
    3. #include<algorithm>  
    4. using namespace std;  
    5.   
    6. JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_callCppFunction (JNIEnv * env, jobject obj)  
    7. {  
    8.     //获取Java中数组属性arrays的id  
    9.     jfieldID fid_arrays = env->GetFieldID(env->GetObjectClass(obj),"arrays","[I");  
    10.     //获取Java中数组属性arrays的对象  
    11.     jintArray jint_arr = (jintArray)env->GetObjectField(obj,fid_arrays);  
    12.     //获取arrays对象的指针  
    13.     jint* int_arr = env->GetIntArrayElements(jint_arr,NULL);  
    14.     //获取数组的长度  
    15.     jsize len = env->GetArrayLength(jint_arr);  
    16.     //打印数组中的值  
    17.     cout<<"数组的值为:";  
    18.     for(int s =0;s<len;s++){  
    19.         cout<<int_arr[s]<<',';  
    20.     }  
    21.     cout<<endl;  
    22.   
    23.     //新建一个jintArray对象  
    24.     jintArray jint_arr_temp = env->NewIntArray(len);  
    25.     //获取jint_arr_temp对象的指针  
    26.     jint* int_arr_temp = env->GetIntArrayElements(jint_arr_temp,NULL);  
    27.     //计数  
    28.     jint count = 0;  
    29.     //偶数位存入到int_arr_temp内存中  
    30.     for(jsize j=0;j<len;j++){  
    31.         if(j%2==0){  
    32.             int_arr_temp[count++] = int_arr[j];       
    33.         }  
    34.     }  
    35.     //打印int_arr_temp内存中的数组  
    36.     cout<<"数组中位置是偶数的值为:";  
    37.     for(jsize k=0;k<count;k++){  
    38.         cout<<int_arr_temp[k]<<',';  
    39.     }  
    40.     cout<<endl;  
    41.   
    42.     //将数组中一段(0-2)数据拷贝到内存中,并且打印出来  
    43.     jint* buffer = new jint[len];  
    44.     //获取数组中从0开始长度为3的一段数据值  
    45.     env->GetIntArrayRegion(jint_arr,0,3,buffer);  
    46.     cout<<"打印数组中0-3一段值:";  
    47.     for(int l=0;l<3;l++){  
    48.         cout<<buffer[l]<<',';  
    49.     }  
    50.     cout<<endl;  
    51.   
    52.     //将数组中的一段(3-7)设置成一定的值,并且打印出来  
    53.     jint* buffers = new jint[4];  
    54.     for(int n=0;n<4;n++){  
    55.         buffers[n] = n+1;  
    56.     }  
    57.     //将buffers这个数组中值设置到数组从3开始长度是4的值中  
    58.     env->SetIntArrayRegion(jint_arr,3,4,buffers);  
    59.     //从新获取数组指针  
    60.     int_arr = env->GetIntArrayElements(jint_arr,NULL);  
    61.     cout<<"数组中3-7这段的值变成了:";  
    62.     for(int m=0;m<len;m++){  
    63.         cout<<int_arr[m]<<',';  
    64.     }  
    65.     cout<<endl;  
    66.   
    67.     //调用C++标准库中的排序方法sort(...),传递一个数组的开始指针和结束指针  
    68.     std::sort(int_arr,int_arr+len);  
    69.     //迭代打印数组中的元素  
    70.     cout<<"数组排序后的结果:";  
    71.     for(jsize i=0;i<len;i++){  
    72.         cout<<int_arr[i]<<',';  
    73.     }  
    74.     cout<<endl;  
    75.     //释放数组指针  
    76.     env->ReleaseIntArrayElements(jint_arr,int_arr,JNI_ABORT);  
    77.   
    78.     //获取Java中对象Father数组属性的id  
    79.     jfieldID fid_obj_arrays = env->GetFieldID(env->GetObjectClass(obj),"objArrays","[Lcom/jni/demo/Father;");  
    80.     //获取Java中对象数组Father属性objArrays的对象  
    81.     jobjectArray jobj_arr = (jobjectArray)env->GetObjectField(obj,fid_obj_arrays);  
    82.     //从对象数组中获取索引值为1的对象Father  
    83.     jobject jobj = env->GetObjectArrayElement(jobj_arr,1);  
    84.     //获取Father对象的class对象    
    85.     jclass clazz_father = env->GetObjectClass(jobj);    
    86.     //获取Father对象中的function方法的id    
    87.     jmethodID id_father_function = env->GetMethodID(clazz_father,"function","()V");    
    88.     //调用Father对象中的function方法  
    89.     env->CallVoidMethod(jobj,id_father_function);     
    90.       
    91.     //在本地创建一个大小为10的对象数组,对象的初始化都是jobj,也就是方法的第三个参数  
    92.     jobjectArray jobj_arr_temp = env->NewObjectArray(10,env->GetObjectClass(jobj),jobj);  
    93.     //获取本地对象数组中第4个对象  
    94.     jobject jobj_temp = env->GetObjectArrayElement(jobj_arr_temp,3);  
    95.     //调用Father对象中的function方法  
    96.     env->CallVoidMethod(jobj_temp,id_father_function);    
    97.   
    98. }  
    99. </span>  

    在Eclipse编译运行结果如下:

    不要以为这就结束了,后面还有很多内容呀!

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    google-glog 开源库分析(一):glog介绍
    homebrew用法
    macos新手入门
    markdown语法_文本效果[转载]
    markdown语法[转载]
    从Search Sort到Join
    实际例子描述和分析“猎豹抢票跨站推荐功能有票刷不到”的疑似bug
    最简单例子图解JVM内存分配和回收
    B树在数据库索引中的应用剖析
    从Count看Oracle执行计划的选择
  • 原文地址:https://www.cnblogs.com/pjdssswe/p/4696114.html
Copyright © 2020-2023  润新知