tags:

views:

98

answers:

1

Good day, masters. Suppose I have a java class A:

class A {
    public A() {}
    public native void setValue(String value);
    public native String getValue();
}

When implementing the native C code, a global char[] variable is used to store the value just be set by native setValue method. The getValue method just return that global char[] variable.

Here comes my question: I create several A objects, and invoke their respective set/get method, I found that they end up writting and readding the same block of memory! Actually the global char[] variable in C native code is totally shared by all A object.

Can anybody give me some in-depth explaination of this behavior? I knew I had a fundmental misunderstanding in terms of the way JNI works. Thanks!

+4  A: 

The problem is that you have the object oriented java on the one side, and the procedural C on the other side. When a java class A is loaded, JNI does not somehow create an object in the C world (this is C - not C++), there is no object-to-object mapping. So JNI loads the corresponding CPP file in the C world once into memory (this is completely normal behavior in C). The compiler sees a bunch of functions and a global reference, there is no need to create multiple instances somehow. When loading a Java class, all the JNI compiler does is to add the C file to the list of files to be compiled.

What you would like to have is a mapping between Java objects and C objects. This can be achieved in several ways, I suggest you read about the proxy pattern in JNI.

To explain very shortly, you have two fundamental ways to achieve this. You can either do it on the C side or on the Java side. When storing the relationship in the C world, you would maintain a hashtable in C where C objects map to Java objects. The other way around, you would have an int object in a Java object that is actually a pointer to a C object in memory. In the C code you would then dereference this pointer (through GetIntField()) and cast to the C object you require.

Of course adding

private String value;

to your Java class A, would indeed work very smootly. Java has a notion of objects, so you could access those Strings from the C world with

env->GetObjectField(obj, "value", "Ljava/lang/String;")

with env being the JNI environment.

David Sauter