将本机指针存储在Java对象中的“正确”方法是什么?
将本机指针存储在Java对象中的“正确”方法是什么?
我可以将指针视为Java int
,如果我碰巧知道本机指针的大小是<= 32位,或者如果我碰巧知道原生指针的大小是<= 64位,那么我会把它当作Java。 但有没有更好或更清洁的方法来做到这一点?
编辑 :从JNI函数返回本机指针正是我不想做的。 我宁愿返回一个代表本机资源的Java对象。 但是,我返回的Java对象必须有一个包含指针的字段,这使我回到原始问题。
或者,是否有更好的方法让JNI函数返回对本机资源的引用?
IIRC, java.util.zip
和java.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位,具体取决于您所使用的系统。