将本机指针存储在Java对象中的“正确”方法是什么?

将本机指针存储在Java对象中的“正确”方法是什么?

我可以将指针视为Java int ,如果我碰巧知道本机指针的大小是<= 32位,或者如果我碰巧知道原生指针的大小是<= 64位,那么我会把它当作Java。 但有没有更好或更清洁的方法来做到这一点?

编辑 :从JNI函数返回本机指针正是我不想做的。 我宁愿返回一个代表本机资源的Java对象。 但是,我返回的Java对象必须有一个包含指针的字段,这使我回到原始问题。

或者,是否有更好的方法让JNI函数返回对本机资源的引用?

IIRC, java.util.zipjava.nio使用long

没有好办法。 在SWT中,使用以下代码:

 int /*long*/ hModule = OS.GetLibraryHandle (); 

并且有一个工具可以通过移动注释来转换32位和64位之间的代码。 丑陋但有效。 如果Sun添加了一个“NativePointer”对象或类似的东西,但事情本来会容易得多。

java.nio.DirectByteBuffer做你想要的。

在内部,它使用private long address来存储指针值。 哇!

使用JNI函数env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct))在C / C ++端创建DirectByteBuffer并将其作为ByteBuffer返回到Java端。 注意:在本机端释放这些数据是你的工作! 它错过了标准DirectBuffer上的自动清洁器。

在Java端,您可以通过以下方式创建DirectByteBuffer:

 ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes); 

把它想象成C的malloc(sizeInBytes)注意:它具有自动清除function,可以释放先前请求的内存。

但是有一些要考虑使用DirectByteBuffer的要点:

  • 如果您错过了直接的ByteBuffer参考,它可以是垃圾收集(GC)。
  • 您可以读取/写入指向结构的值,但要注意偏移量和数据大小。 编译器可能会为填充添加额外的空间,并在结构中打破假设的内部偏移。 带指针的结构(步幅是4或8个字节?)也会困扰你的数据。
  • 直接ByteBuffers很容易作为本机方法的参数传递,并将其作为返回值返回。
  • 您必须在JNI端转换为正确的指针类型。 env->GetDirectBufferAddress(buffer)返回的默认类型为void*
  • 创建后无法更改指针值。
  • 你的工作是释放以前为本机缓冲区分配的内存。 与env->NewDirectByteBuffer()一起使用的那些。

一种更好的方法可能是将它存储在一个字节数组中,因为本机指针首先不是Java-ish。 int s和long s最好保留用于存储数值。

我假设这是从一些JNI代码返回的指针,我的建议就是不要这样做 🙂

理想情况下,JNI代码应该传递给资源的某种逻辑引用,而不是实际的指针?

关于你的问题,没有什么可以想到存储指针的更简洁的方法 – 如果你知道你有什么,那么根据需要使用int或long或byte []。

你可以看看C#使用IntPtr类型处理它的方式。 通过创建自己的类型来保存指针,相同的类型可以用作32位或64位,具体取决于您所使用的系统。