使用JNI在C中访问Java对象中的Java对象

use*_*243 5 c c++ java java-native-interface

我对JNI比较陌生,并且已经解决了使用JNI在Java对象中弄乱整数和数组的基础知识.现在我正在尝试修改/访问Java对象中的Java对象.

我一直在互联网和Stack Overflow上搜索,还没有找到如何做到这一点.

这是一个例子.

在Java中:

public class ObjectOne
{
    private byte[] buff;
    ...
    ...
}

public class ObjectTwo
{
    private ObjectOne obj;
    ...
    ...
}
Run Code Online (Sandbox Code Playgroud)

在JNI中,如何通过ObjectTwo从ObjectOne访问"buff"?我试过这样的事......

JNIEXPORT void JNICALL Java_accessBuffThroughObjectTwo(JNIEnv *env, jobject obj, jobject objectTwo)
{
    jclass clazz;
    jclass bufferClazz;
    jobject bufferJObject;

    clazz = (*env)->GetObjectClass(env, objectTwo);
    fid = (*env)->GetFieldID(env, clazz, "obj", "Ljava/lang/Object;");
    bufferJObject = (*env)->GetObjectField(env, javascsicommand, fid);
    bufferClazz = (*env)->GetObjectClass(env, bufferJObject);  <-- Fails here for Access Violation
    fid = (*env)->GetFieldID(env, bufferClazz, "buff", "[B");
}
Run Code Online (Sandbox Code Playgroud)

对我做错的任何帮助?

mab*_*aba 15

在尝试代码时,您可以轻松添加一些这样的断言:

JNIEXPORT void JNICALL Java_accessBuffThroughObjectTwo(JNIEnv *env, jobject obj,  jobject objectTwo) {
    jclass clazz;
    jclass bufferClazz;
    jobject bufferJObject;
    jfieldID fid;

    clazz = (*env)->GetObjectClass(env, objectTwo);
    assert(clazz != NULL);
    fid = (*env)->GetFieldID(env, clazz, "obj", "Ljava/lang/Object;");
    assert(fid != NULL);
    bufferJObject = (*env)->GetObjectField(env, javascsicommand, fid);
    assert(bufferJObject != NULL);
    bufferClazz = (*env)->GetObjectClass(env, bufferJObject);
    assert(bufferClazz != NULL);
    fid = (*env)->GetFieldID(env, bufferClazz, "buff", "[B");
    assert(fid != NULL);
}
Run Code Online (Sandbox Code Playgroud)

这样做,您将首先看到第一个fid将为NULL.那是因为ObjectTwo该类没有任何类型的字段java.lang.Object.您应该将行更改为这样(但添加正确的包而不是com/package):

fid = (*env)->GetFieldID(env, clazz, "obj", "Lcom/package/ObjectOne;");
Run Code Online (Sandbox Code Playgroud)

如果再次运行,您会发现fid不再为null,并且断言将通过.

正如其他人所说,我相信javascsicommand应该是objectTwo.

现在断言失败的下一个地方正在启用bufferJObject.这是因为该字段存在,但该对象为NULL,如果您检查您的Java代码,您将注意到该obj字段从未实例化,并且是null.

将您的Java代码更改为以下内容:

public class ObjectTwo
{
    private ObjectOne obj = new ObjectOne();
    ...
    ...
}
Run Code Online (Sandbox Code Playgroud)

您现在将传递断言,甚至传递所有其他断言.

总结一下,您正在访问一个null对象并尝试在其上调用反射:

bufferClazz = (*env)->GetObjectClass(env, bufferJObject); <-- The bufferJObject was NULL
Run Code Online (Sandbox Code Playgroud)