美好的一天,主人。假设我有一个java类A:
class A {
public A() {}
public native void setValue(String value);
public native String getValue();
}
实现本机C代码时,全局char []变量用于存储刚才由本机setValue
方法设置的值。 getValue
方法只返回全局char []变量。
我的问题出现了:我创建了几个A对象,并调用它们各自的set / get方法,我发现它们最终会写入并读取相同的内存块!实际上,C本机代码中的全局char []变量完全由所有A对象共享。
有人能给我一些深入解释这种行为吗?我知道在JNI的工作方式上我有一个基本的误解。谢谢!
答案 0 :(得分:7)
问题是你一边是面向对象的java,另一边是程序C。当加载java类A时,JNI不会以某种方式在C世界中创建对象(这是C - 而不是C ++),没有对象到对象的映射。因此,JNI将C world 中的相应CPP文件一次加载到内存中(这在C中是完全正常的行为)。编译器看到一堆函数和一个全局引用,不需要以某种方式创建多个实例。加载Java类时,所有JNI编译器都将C文件添加到要编译的文件列表中。
您希望拥有的是Java对象和C对象之间的映射。这可以通过几种方式实现,我建议你阅读JNI中的代理模式。
很快就会解释,你有两种基本的方法来实现这一目标。您可以在C端或Java端执行此操作。在C世界中存储关系时,您将在C中维护一个哈希表,其中C对象映射到Java对象。反过来说,你会在Java对象中有一个int对象,它实际上是指向内存中C对象的指针。在C代码中,您将取消引用此指针(通过GetIntField())并转换为您需要的C对象。
当然添加
private String value;
到你的Java类A,确实非常流畅。 Java有一个对象的概念,因此您可以使用
从C世界访问这些字符串env->GetObjectField(obj, "value", "Ljava/lang/String;")
env是JNI环境。