27

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

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

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

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

4

6 回答 6

24

IIRC,两者java.util.zip都只java.nio使用long.

于 2008-12-03T14:47:52.023 回答
5

java.nio.DirectByteBuffer做你想做的事。

在内部,它使用 aprivate 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)注意:它具有自动清理程序,可释放先前请求的内存。

但是使用 DirectByteBuffer 有几点需要考虑:

  • 如果您错过了直接的 ByteBuffer 引用,它可能会被垃圾收集 (GC)。
  • 您可以读取/写入指向结构的值,但要注意偏移量和数据大小。编译器可能会为填充添加额外的空间并破坏您假定的结构内部偏移量。带有指针的结构(步幅是 4 还是 8 字节?)也会让您的数据感到困惑。
  • Direct ByteBuffers 很容易作为本地方法的参数传递,也很容易将其作为返回值返回。
  • 您必须在 JNI 端强制转换为正确的指针类型。返回的默认类型env->GetDirectBufferAddress(buffer)void*
  • 一旦创建,您将无法更改指针值。
  • 您的工作是释放先前分配给本机缓冲区的内存。你用的那些env->NewDirectByteBuffer()
于 2016-03-21T02:18:31.913 回答
3

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

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

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

于 2008-12-03T14:49:16.310 回答
2

更好的方法可能是将它存储在字节数组中,因为本机指针首先不是非常Java-ish。ints 和longs 更好地保留用于存储数值。

于 2008-12-03T14:32:18.327 回答
2

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

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

至于您的问题,没有想到一种更简洁的存储指针的方法-如果您知道自己拥有什么,则根据需要使用 int 或 long 或 byte[] 。

于 2008-12-03T14:32:46.110 回答
1

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

于 2008-12-03T14:41:33.970 回答