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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11803927/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:25:48  来源:igfitidea点击:

Accessing a Java object in a Java object in C using JNI

javac++cjava-native-interface

提问by user1575243

I'm relatively new to JNI and have gotten down the basics of messing with integers and arrays in Java objects using JNI. Now I'm trying to modify/access a Java object within a Java object.

我对 JNI 比较陌生,并且已经掌握了使用 JNI 在 Java 对象中处理整数和数组的基础知识。现在我正在尝试修改/访问 Java 对象中的 Java 对象。

I've been searching on the internet and on Stack Overflow and have yet to find out how to do this.

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

Here's the example.

这是示例。

In Java:

在 Java 中:

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

public class ObjectTwo
{
    private ObjectOne obj;
    ...
    ...
}

In JNI, how do I access "buff" from ObjectOne through ObjectTwo? I tried something like this...

在 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");
}

Any help on what I'm doing wrong?

对我做错了什么有帮助吗?

回答by maba

When trying your code you could easily add some assertions like this:

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

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);
}

Doing so you will first see that the first fidwill be NULL. That is because the ObjectTwoclass does not have any fields of type java.lang.Object. You should change the line to look like this (but add the correct packages instead of com/package):

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

fid = (*env)->GetFieldID(env, clazz, "obj", "Lcom/package/ObjectOne;");

If you run again you will find that the fid is no longer null and the assertion will pass.

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

As others have suggested I believe that the javascsicommandshould be objectTwo.

正如其他人所建议的那样,我认为javascsicommand应该是objectTwo.

Now the next place where the assertion will fail is on bufferJObject. That is because the field exists but the object is NULL and if you check your java code you will notice that the objfield is never instantiated and is null.

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

Change your java code to something like this:

将您的 Java 代码更改为如下所示:

public class ObjectTwo
{
    private ObjectOne obj = new ObjectOne();
    ...
    ...
}

You will now pass the assertion and even pass all other assertions.

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

To summarize you were accessing a nullobject and trying to invoke reflection on it:

总而言之,您正在访问一个null对象并尝试对其进行反射:

bufferClazz = (*env)->GetObjectClass(env, bufferJObject); <-- The bufferJObject was NULL