我试图了解如何从JNI层使用GetDirectBufferAddress。为了理解,我构建了一个非常简单的示例:

public class my_image_info {
  static {
      System.loadLibrary("my_jni");
  }
  private java.nio.ByteBuffer image_info_bb;
  native static void initc( java.nio.ByteBuffer bb );
  my_image_info()
    {
    image_info_bb = java.nio.ByteBuffer.allocateDirect( 5 * 4 );
    initc( image_info_bb );
    }
  public java.nio.ByteBuffer getBB() {
    return image_info_bb;
  }
  static public void main(String argv[]) {
    my_image_info fii = new my_image_info();
    java.nio.ByteBuffer bb = fii.getBB();
    System.out.println("1: " + bb.getInt(0));
    System.out.println("2: " + bb.getInt(4));
    System.out.println("3: " + bb.getInt(8));
    System.out.println("4: " + bb.getInt(12));
    System.out.println("5: " + bb.getInt(16));
}
然后从本地JNI层:
JNIEXPORT void JNICALL Java_my_1image_1info_initc
  (JNIEnv *env, jclass cls, jobject jobj)
{
  int *iBuf = (*env)->GetDirectBufferAddress(env, jobj);
  iBuf[0] = -2;
  iBuf[1] = -1;
  iBuf[2] = 0;
  iBuf[3] = 1;
  iBuf[4] = 2;
}
如果我使用openjdk在此处(debian/linux wheezy amd64)上运行此示例,请执行以下操作:
$ java -version
java version "1.6.0_34"
OpenJDK Runtime Environment (IcedTea6 1.13.6) (6b34-1.13.6-1~deb7u1)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)
这是我看到的:
1: -16777217
2: -1
3: 0
4: 16777216
5: 33554432
我理解索引2和3的值。但是所有其他值对我来说都没有任何意义,我原本希望这样:
1: -2
2: -1
3: 0
4: 1
5: 2
我从JNI中的ByteBuffer用法中误解了什么?

最佳答案

我从文档中错过的是默认情况下java.nio.ByteBuffer实际上是使用BIG_ENDIAN字节顺序。这就解释了我在LITTLE_ENDIAN系统上看到的行为。参见ref here
我的代码现在显示为:

image_info_bb = java.nio.ByteBuffer.allocateDirect( 5 * 4 );
image_info_bb.order( java.nio.ByteOrder.LITTLE_ENDIAN );
似乎默认情况下它始终是BIG_ENDIAN,并且到目前为止,还没有做出任何努力来提供LITTLE_ENDIAN的API,如错误报告here(JDK-5043362:(bf)NewDirectByteBuffer始终具有ByteOrder.BIG_ENDIAN)中所述。

文档最近已更新,以反射(reflect)以下内容:
  • JDK-8225152 : Release Note: JNI NewDirectByteBuffer Creates Direct Buffer That Is java.nio.ByteOrder.BIG_ENDIAN
  • 10-08 13:41
    查看更多