我对如何正确处理JNI中的关联(或行为)有疑问。
假设在共享库中有两个类,分别是NativeClass1
和NativeClass2
。 NativeClass1
具有方法void fooNative(NativeClass2* nativeObj)
,该方法允许它对类型为NativeClass2
的对象执行某些操作。
对于这些类中的每一个,都定义了一个Java类来包装相应的本机对象(JavaClass1
和JavaClass2
,每个类都有一个long
私有成员,该成员指向动态分配的类型为NativeClass1
和)。
我希望NativeClass2
也具有方法JavaClass1
(以及相应的本机方法public void fooJava(JavaClass2 obj)
,该方法将在强制转换指针后最终调用private native void call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr)
)。
如何从NativeClass1::void fooNative(NativeClass2* nativeObj)
获取基本的长指针(指向NativeClass2
的成员)以调用JavaClass2
(假设您将void JavaClass1::call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr)
的指针作为第一个参数传递)?
我想到了两种方法:
为NativeClass1
中的长指针创建一个公共的getter方法。
但是每个人都可以访问实际的本机对象,创建另一个共享库,在JavaClass2
的void指针上执行delete ptr
或以其他方式破坏本机对象。
而不是将指针传递给NativeClass2
对象(作为NativeClass2
的第二个参数,而是传递类型为call_fooNative(...)
的实际java对象,并使用JavaClass2
和getFieldId
确定指针(允许在私有对象上使用)成员,如Java本地接口:程序员指南和规范,作者Liang Liang所言,“ 10.9违反访问控制规则”。
就设计和安全性而言,哪种方法是正确的?
最佳答案
如何从JavaClass2获取基本的长指针(指向NativeClass2),以便调用void JavaClass1 :: call_fooNative(long nativeObject1Ptr,long nativeObject2Ptr)(假设您将指向NativeClass1的指针作为第一个参数传递)?
您的第一种方法可能是合理的。这是SWIG使用的方法。
SWIG是一个开放源代码工具,可为C ++代码生成Java包装器。如果要包装许多类或方法,则可能要考虑使用它。
例如,以下是SWIG生成的一些代码(更改了类名):
public class Foo {
private long swigCPtr;
protected boolean swigCMemOwn;
public Foo(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
public static long getCPtr(Foo obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
...
但是每个人都可以访问实际的本机对象,创建另一个共享库,对NativeClass2的void指针执行delete ptr或以其他方式破坏本机对象。
不一定每个人都可以,只有Java和本地代码可以访问对NativeClass2特定实例的引用。
而不是将指针传递给NativeClass2对象(作为call_fooNative(...的第二个参数),而是传递类型为JavaClass2的实际Java对象,并使用getFieldId和getLongField确定指针...
这不一定会阻止从Java访问指针。 Java代码可以use reflection to access private fields。