java—重新解释底层位模式并将其写入and数组或字段的最有效方法是什么?

a0x5cqrl  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(264)

使用 Unsafe.putXXX 可以将基元类型放入数组或对象字段中。
但是像下面这样的代码会产生错误。

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Arrays;

public class Main {

  public static void main(String[] args) {
    VarHandle varHandle = MethodHandles.arrayElementVarHandle(long[].class);

    byte[] array = new byte[32];

    printArray(array);
    varHandle.set(array, 1, 5);
    printArray(array);

    System.out.println(varHandle.get(array, 1));
  }

  private static void printArray(byte[] array) {
    System.out.println(Arrays.toString(array));
  }

}
Exception in thread "main" java.lang.ClassCastException: Cannot cast [B to [J
    at java.base/java.lang.Class.cast(Class.java:3780)
    at Main.main(Main.java:15)

还有 bytes 可写为:

byte[] array = new byte[32];
long v = 5,
int i = 8;
int high = (int) (v >>> 32);
int low = (int) v;
array[i + 0] = (byte) (high >>> 24);
array[i + 1] = (byte) (high >>> 16);
array[i + 2] = (byte) (high >>> 8);
array[i + 3] = (byte) high;
array[i + 4] = (byte) (low >>> 24);
array[i + 5] = (byte) (low >>> 16);
array[i + 6] = (byte) (low >>> 8);
array[i + 7] = (byte) low;

有没有一种有效的方法来重新解释不同的类型并将它们写入字段和数组 Unsafe 但同样有效。
任何特殊情况下,编译器或jit将识别意图并进行相应的优化。

w8ntj3qf

w8ntj3qf1#

为了 byte[] 特别是你可以使用 MethodHandles::byteArrayViewVarHandle :

public static void main(String[] args) {
    VarHandle varHandle = MethodHandles.byteArrayViewVarHandle(long[].class,
                                                               ByteOrder.nativeOrder());

    byte[] array = new byte[32];

    printArray(array);
    varHandle.set(array, 1, 5);
    printArray(array);

    System.out.println(varHandle.get(array, 1));
}

private static void printArray(byte[] array) {
    System.out.println(Arrays.toString(array));
}

有一些箍你必须跳过与varhandles使他们一样快不安全;
确保varhandle本身是常量,这可以通过将它放入静态final字段并从那里访问它来完成。
确保varhandle调用是准确的。这里这意味着将第二个参数转换为long,因为varhandle也排除了long(在最新的jdk中,您可以使用 VarHandle::withInvokeExactBehavior 执行)。
通过在执行强制转换的helper方法中 Package varhandle集和get调用,可以简化这一过程:

private static final VarHandle LONG_ARR_HANDLE 
        = MethodHandles.byteArrayViewVarHandle(long[].class,
                                               ByteOrder.nativeOrder());

public static void setLong(byte[] bytes, int index, long value) {
    LONG_ARR_HANDLE.set(bytes, index, value);
}   

public static long getLong(byte[] bytes, int index) {
    return (long) LONG_ARR_HANDLE.get(bytes, index);
}

相关问题