处理与JNI的关联

Handling association with JNI

本文关键字:关联 JNI 处理      更新时间:2023-10-16

我有一个关于如何正确处理JNI中的关联(或依赖)的问题。

假设在你的共享库中有两个类,NativeClass1NativeClass2NativeClass1有一个方法void fooNative(NativeClass2* nativeObj),该方法允许它对NativeClass2类型的对象执行一些操作。

对于这些类中的每一个,定义了一个java类来包装相应的本机对象(JavaClass1JavaClass2,每个都有一个long私有成员,分别指向类型为NativeClass1NativeClass2的动态分配的本机对象)。

我希望JavaClass1也有一个方法public void fooJava(JavaClass2 obj)(以及相应的本地方法private native void call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr),该方法将在转换指针后最终调用NativeClass1::void fooNative(NativeClass2* nativeObj))。

如何从JavaClass2获得底层的长指针(指向NativeClass2)成员,以便调用void JavaClass1::call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr)(假设您传递指向NativeClass1的指针作为第一个参数)?

我想到了两种方法:

  1. JavaClass2中的长指针创建一个公共getter方法。

但是每个人都可以访问实际的本机对象,创建另一个共享库,对NativeClass2的void指针执行delete ptr操作,或者以其他方式破坏本机对象。

  • 不将指针传递给NativeClass2对象(作为call_fooNative(...)的第二个参数),而是传递JavaClass2类型的实际java对象,并确定getFieldIdgetLongField的指针(这是在私有成员上允许的,如盛亮的《java本机接口:程序员指南和规范》中所述,"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代码可以使用反射访问私有字段。