java - 直接字节缓冲区

标签 java java-native-interface

我正在使用 JNI 测试直接 ByteBuffer(java.nio.ByteBuffer)。所以下面的代码试图:

  1. 在Java中将值直接放入ByteBuffer
  2. 在 C++ 中更改值
  3. 获取Java中的值

我想知道我到底哪里做错了? C++ 代码设法从 Java 获取数据,但 C++ 中的更改并未反射(reflect)在 Java 中。

这是我在 java 上做的:

public static void main(String[] args){
    ByteBuffer bb = ByteBuffer.allocateDirect(3);
    byte[] b = {122,121,120};
    System.out.println("1: " + new String(b));
    bb.put(b);

    new JNI.process(bb);

    byte[] c = new byte[3];
    c[0] = bb.get();
    System.out.println("4: " + new String(c));
}

这是我对 JNI 函数所做的:

JNIEXPORT void JNICALL Java_MarsJNI_mapreduce
  (JNIEnv *env, jobject thisObj, jobject output){
    char *out = (char*)env->GetDirectBufferAddress(output);
    printf("2: %s\n", out);
    out = "ABC";
    printf("3: %s\n", out);
}

我得到的结果是:

1: zyx
2: zyx
3: ABC
Exception in thread "main" java.nio.BufferUnderflowException
    at java.nio.Buffer.nextGetIndex(Buffer.java:474)
    at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:208)
    at MarsJNI.main(MarsJNI.java:21)

最佳答案

第一个问题:参见@TedBigham 的回答。您还可以使用 buf.rewind()

第二个问题:您只将缓冲区的第一个字节复制到c,而不是整个缓冲区。做:

byte[] c = new byte[3];
bb.rewind();
bb.put(c);
System.out.println("4: " + new String(c));

第三个问题:您的 C++ 代码确实:

char *out = (char*)env->GetDirectBufferAddress(output);
// ...
out = "ABC";

但是您在这里所做的是创建 { 'A', 'B', 'C', 0 } 并将 out 分配给它;您实际上并没有修改缓冲区的内容。你应该这样做:

memcpy(out, "ABC", 3);

第四个问题:当你从一个byte[]中创建一个String时,你应该指定编码:

new String(c, StandardCharsets.UTF_8);

关于java - 直接字节缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22423147/

相关文章:

c++ - JNI-C++ 使用 jni 时如何清理 jfloat 等原语

Java - 合并两个数组而不重复(不允许使用库)

java - 在 ScrollPane 中添加多个 jlabel

java - 如何在JAVA中获取Internet Explorer的文档模式

调试 JNI 模块中的特定访问冲突

Java 小程序问题 : dll already loaded in another classloader

java - 试图在java中的Arraylist中找到一个对象的所有出现

java - 如何手动测试编译好的GWT项目?

java - JNI 不会在 cmake 环境中创建 jclasses