先说一下为什么要写这个, 这个问题是我面试中被问到的问题:
在java中有一个类A.java ,在C++中也有一个类A.cpp. 这两个类的功能函数完全对应.如何建立关联,使操作java层的对象,就相当于操作C++层的对象呢?
解释一下这个问题,首先当我们在java层new 出一个A1Java
对象时,对应的C++
层也要创建一个A1Cpp
对象.当我们调用A1java
对象的某个方法时,映射到C++层也要调用对象A1Cpp
的方法.
看到这个问题,我第一个想法是,当我在java
层new
出对象时,调用JNI
函数在C++
层创建对象, 这样就会有一个问题,当我们new
出第二个对象时,我们之前创建的对象改如何保存,我们可以在C++
层建立一个map
来保存之前创建的对象,用java层的jclass
作为key
,这样就可以在java对象销毁的时候,找到C++
对象销毁.
但是这样的回答,显然让面试官感到不满意.下来我仔细想想,我的回答确实没有很吻合对称关联
.说到底我是用一个中间的缓存来解决java
和C++
层的关联.其实还有一种更好的办法.
想一下,我们为什么需要一个map
呢,无非不就是让java
对象和C++
对象关联起来.我们一般通过什么可以找到C++
对象呢?显然是指针
也就是对象的地址
.也就是说每一个java对象
都对应着一个C++
对象地址,如果我们和java对象
和这个地址关联起来的话,就可以找到C++
对象了.显然,我们可以在java 类
里增加一个变量来存放C++
层的指针,这样我们在构造函数的时候,调用JNI
函数去构造C++
层对象,然后将这个对象的地址,用JNI
函数会设到该java对象
,这样我们在操作java层对象方法时,将这个对象的地址传递到JNI
层,就可以用这个地址,找到相对应的C++
对象了,然后操作相应的函数.这同时也省去了中间的map
,更加符合对称关联
的表述了.
java层:
class A{
private long nativeOjbHandle;
private String tag;
public A(String tag){
this.tag = tag;
initNative();
}
public native void initNative();
private native String getName();
}
JNI层:
initNativeA(JNIEnv *env, jobject instance){
NativeA *objNative = new NativeA();
jclass clazz = (jclass)env->GetObjectClass(instance);
jfieldID fid = (jfieldID)(*env).GetFieldID(clazz, "nativeOjbHandle", "J");
env->SetIntField(thiz, fid, (jlong)objNative);
}
jstring
getNative (JNIEnv *env, jobject instance ){
jclass objClazz = (jclass)env->GetObjectClass(instance);//obj为对应的JAVA对象
jfieldID fid = env->GetFieldID(objClazz, "nativeOjbHandle", "J");
jlong p = (jlong)env->GetObjectField(obj, fid);
NativeA *nativeA = (NativeA *)p;
}
方法二:C++对象持有JAVA对象的引用
在C++
类中创建一个jint
类型的变量(如jint mObj
),用于储存JAVA
对象的引用
在创建C++对象时,储存JAVA对象的引用
jobject javaObjCls = (jobject)env->NewGlobalRef(thiz);//thiz为JAVA对象
NativeAObj->javaObj = (jint)javaObjCls;
网友评论