簡體   English   中英

如何從C ++發送2D數組並在Java中編輯值,然后通過JNI以2D數組發送回C ++

[英]How to send a 2D array from C++ and edit the values in Java and send back to C++ in 2D array via JNI

根據主題,我有一個名為cells的2D數組,其中包含C ++中的某些值。

我想將此2D數組發送到我的Java文件中,它將替換其中的一些值。 我有什么方法可以用Java從C ++中“接收”數組嗎?

目前,我可以使用C ++從Java打印內容。 我的源代碼如下:

C ++源代碼:

//JNI
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <vector>

//jvm
JavaVMOption options[1];
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
long status;
jclass cls;
jmethodID mid;

typedef std::vector<std::vector<int>> IntMatrix;
IntMatrix cells;

//fn header
template<std::size_t OuterDim, std::size_t InnerDim>
jobjectArray to_java(JNIEnv *env, int(&arr)[OuterDim][InnerDim]);
std::vector<std::vector<int> > from_java(JNIEnv *env, jobjectArray arr);
jobjectArray v2jObs(IntMatrix v2D);




int main(){
    cells = { { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, { 0, 1, 1, 1, 1, 1, 0, 1, 0, 1 }, { 0, 1, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1 }, { 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 1, 1, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1 }, { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };

    options[0].optionString = "-Djava.class.path=C:\\Users\\Downloads\\ConsoleApplication2\\ConsoleApplication2";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_2;
    vm_args.nOptions = 1;
    vm_args.options = options;
    status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

    //int cells[10][10]; // my 2d array
    //for (int i = 0; i < 10; i++){
    //  for (int j = 0; j < 10; j++){
    //      cells[i][j] = 1;
    //  }
    //}



    if (status != JNI_ERR){
        cls = env->FindClass("Sample2");
        if (cls != 0){
            mid = env->GetStaticMethodID(cls, "intArrayMethod", "([[I)[[I");
            if (mid != 0){
                jobjectArray java_cells = static_cast<jobjectArray>(env->CallStaticObjectMethod(cls, mid, v2jObs(cells)));
                std::vector<std::vector<int> > cpp_cells = from_java(env, java_cells);
                for (int i = 0; i < 10; i++){
                    for (int j = 0; j < 10; j++){
                        printf("%d", cpp_cells[i][j]);
                    }
                }
            }
        }
        jvm->DestroyJavaVM();
        return 0;
    }
    else{
        return 1;
    }


}


// The template bit here is just to pick the array dimensions from the array
// itself; you could also pass in a pointer and the dimensions. 
template<std::size_t OuterDim, std::size_t InnerDim>
jobjectArray to_java(JNIEnv *env, int(&arr)[OuterDim][InnerDim]) {
    // We allocate the int array first
    jintArray    inner = env->NewIntArray(InnerDim);
    // to have an easy way to get its class when building the outer array
    jobjectArray outer = env->NewObjectArray(OuterDim, env->GetObjectClass(inner), 0);

    // Buffer to bring the integers in a format that JNI understands (jint
    // instead of int). This step is unnecessary if jint is just a typedef for
    // int, but on OP's platform this appears to not be the case.
    std::vector<jint> buffer;

    for (std::size_t i = 0; i < OuterDim; ++i) {
        // Put the data into the buffer, converting them to jint in the process
        buffer.assign(arr[i], arr[i] + InnerDim);

        // then fill that array with data from the input
        env->SetIntArrayRegion(inner, 0, InnerDim, &buffer[0]);
        // and put it into the outer array
        env->SetObjectArrayElement(outer, i, inner);

        if (i + 1 != OuterDim) {
            // if required, allocate a new inner array for the next iteration.
            inner = env->NewIntArray(InnerDim);
        }
    }

    return outer;
}


// Note that this function does not return an array but a vector of vectors
// because 2-dimensional Java arrays need not be rectangular and have
// dynamic size. It is not generally practical to map them to C++ arrays.
std::vector<std::vector<int> > from_java(JNIEnv *env, jobjectArray arr) {
    // always on the lookout for null pointers. Everything we get from Java
    // can be null.
    jsize OuterDim = arr ? env->GetArrayLength(arr) : 0;
    std::vector<std::vector<int> > result(OuterDim);

    for (jsize i = 0; i < OuterDim; ++i) {
        jintArray inner = static_cast<jintArray>(env->GetObjectArrayElement(arr, i));

        // again: null pointer check
        if (inner) {
            // Get the inner array length here. It needn't be the same for all
            // inner arrays.
            jsize InnerDim = env->GetArrayLength(inner);
            result[i].resize(InnerDim);

            jint *data = env->GetIntArrayElements(inner, 0);
            std::copy(data, data + InnerDim, result[i].begin());
            env->ReleaseIntArrayElements(inner, data, 0);
        }
    }

    return result;
}


jobjectArray v2jObs(IntMatrix v2D){
    int y = v2D.size();
    int x = v2D[0].size();
    jint **arr2D = new jint*[y];

    jintArray inner = env->NewIntArray(x);
    jobjectArray outer = env->NewObjectArray(y, env->GetObjectClass(inner), 0);

    for (unsigned i = 0; (i < y); i++)
    {
        arr2D[i] = new jint[x];
        for (unsigned j = 0; (j < x); j++)
        {
            arr2D[i][j] = v2D[i][j];
        }
        env->SetIntArrayRegion(inner, 0, x, arr2D[i]);
        env->SetObjectArrayElement(outer, i, inner);
    }
    return outer;

}

IntMatrix jObs2v(jobjectArray arr2D){
    int y = env->GetArrayLength(arr2D);
    //int x = env->GetObjectLength(env->GetObjectArrayElement(arr2D, 0));
    IntMatrix result(y);
    return result;
}

Java的:

public class Sample2{
    public static void main(String []args){
        //
    }

    public static int[][] intArrayMethod(int[][] n){
        for (int i = 0; i < 10; i++){
            for (int j = 0; j < 10; j++){
                n[i][j] = 2;
            }
        }
        return n;
    }
}

我是否必須在Java程序中包含一些代碼來“接收”來自C ++的cell 2D數組值? 我整夜都在搜索,但無法正常工作。 請幫忙 !!!

我將類重命名為SampleSO ,使Array為3x3,並使intArrayMethod方法的值是每個單元格的兩倍。 為簡單起見,我沒有使用您的v2jObs函數和您的IntMatrix類型。

我復制/粘貼了兩個C ++函數to_javafrom_java嚴格未經修改 (在下面省略)

java類:

public class SampleSO{
    public static void main(String []args){}

    public static int[][] intArrayMethod(int[][] n){
        for (int i = 0; i < 3; i++){
            for (int j = 0; j < 3; j++){
                n[i][j] *= 2;
            }
        }
        return n;
    }
}

C ++源代碼(沒有to_javafrom_java

#include <jni.h>
#include <cstring>
#include <vector>

int wmain( int argc, wchar_t * argv[] ) {

    JavaVMOption options[1];
    options[0].optionString = "-Djava.class.path=C:/Users/manuel/Documents/Visual Studio 2010/Projects/JavaArray";

    JavaVMInitArgs vm_args;
    memset( &vm_args, 0, sizeof( vm_args ) );

    vm_args.version = JNI_VERSION_1_2;
    vm_args.nOptions = 1;
    vm_args.options = options;

    JavaVM *jvm;
    JNIEnv *env;
    jint status = JNI_CreateJavaVM( &jvm, (void**)&env, &vm_args );
    printf( "JNI_CreateJavaVM said %d\n", status );
    if ( status != JNI_ERR ) {
        jclass cls = env->FindClass( "SampleSO" );
        if ( cls != nullptr ) {
            printf( "Class Found\n" );
            jmethodID mid = env->GetStaticMethodID( cls, "intArrayMethod", "([[I)[[I");
            if ( mid != nullptr ) {
                printf( "Method Found\n" );
                int Array[3][3] = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, };
                jobjectArray java_cells = static_cast<jobjectArray>( env->CallStaticObjectMethod( cls, mid, to_java( env, Array ) ) );
                printf( "Method Called\n" );
                std::vector<std::vector<int> > Result = from_java( env, java_cells );
                printf( "Dumping Result:\n" );
                for ( size_t RowIndex = 0; RowIndex < Result.size(); ++RowIndex ) {
                    for ( size_t ColIndex = 0; ColIndex < Result[ RowIndex ].size(); ++ColIndex ) {
                        printf( "%d ", Result[ RowIndex ][ ColIndex ] );
                    } // end for
                    printf( "\n" );
                } // end for
            } // endif
        } // endif
    } // endif

    return 0;

} // wmain

結果: 在VS2010,Java 1.6 x86中執行的結果

請注意:

  • Windows 7 64位,Oracle Java x86 1.6,Visual Studio 2010
  • 沒有內存清理
  • 您可以使用ExceptionCheck ,或ExceptionOccurred ,然后ExceptionClear在C ++中,JNI調用之后。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM