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

使用JNI访问C中Java对象中的Java对象,java,c++,c,java-native-interface,Java,C++,C,Java Native Interface,我对JNI比较陌生,已经掌握了使用JNI在Java对象中处理整数和数组的基本知识。现在,我尝试在Java对象中修改/访问Java对象 我一直在互联网和堆栈溢出上搜索,还没有找到如何做到这一点 下面是一个例子 在Java中: public class ObjectOne { private byte[] buff; ... ... } public class ObjectTwo { private ObjectOne obj; ... ... }

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

我一直在互联网和堆栈溢出上搜索,还没有找到如何做到这一点

下面是一个例子

在Java中:

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

public class ObjectTwo
{
    private ObjectOne obj;
    ...
    ...
}
在JNI中,如何从ObjectOne到ObjectTwo访问“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");
}
JNIEXPORT void JNICALL Java_accessBuffThroughObjectTwo(JNIEnv*env、jobject obj、jobject objectTwo)
{
jclass-clazz;
jclass bufferClazz;
jobject缓冲jobject;
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);GetFieldID(env,bufferClazz,“buff”,“B”);
}

关于我做错了什么有什么帮助吗?

在尝试代码时,您可以很容易地添加如下断言:

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);
}
public class ObjectTwo
{
    private ObjectOne obj = new ObjectOne();
    ...
    ...
}
这样做首先会看到第一个
fid
将为空。这是因为
ObjectTwo
类没有任何类型为
java.lang.Object
的字段。您应该将行更改为如下所示(但添加正确的包,而不是
com/package
):

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

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

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

将java代码更改为以下内容:

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);
}
public class ObjectTwo
{
    private ObjectOne obj = new ObjectOne();
    ...
    ...
}
现在,您将传递断言,甚至传递所有其他断言

概括地说,您正在访问
null
对象并试图对其调用反射:

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

bufferClazz=(*env)->GetObjectClass(env,bufferJObject);第一步是检查每个JNI调用是否失败。第二步:什么是
javascsicommand
?我相信您将
obj
实例的值传递给了。请参阅正确的描述符:
jobject GetObjectField(JNIEnv*env,jobject对象,jfieldID fieldID)
也许您想传递
objectTwo
而不是
javascsicommand
?您无法访问另一个对象的私有字段。您需要提供getter、更改访问权限关键字或打开访问运行时。@qrtt1是的,您可以使用JNI访问私有字段。感谢您的详细响应。我一定会对断言进行初始化并检查NULL。我想当你谈论访问NULL对象时,你说到点子上了。我想这就是让我访问NULL对象的原因violation@user1575243如果你认为我的答案有用,那么请将答案标记为已接受!@user1575243如果像我这样的人花一些时间设置编码环境nments,开始调试会话并尝试解决其他人的问题,那么你至少可以期望他们接受他们认为有用的答案…对此感到抱歉。我不知道接受答案如此重要。答案被接受。