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

2024-01-11

Using 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 会识别意图并进行相应优化的任何特殊情况。


For 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 跳过一些障碍,才能使其与 Unsafe 一样快;

  1. 确保 VarHandle 本身是常量,这可以通过将其放入静态最终字段并从那里访问它来完成。
  2. 确保 VarHandle 调用准确。这里这意味着 由于 VarHandle 除外,因此将第二个参数强制转换为 long 也长。 (在最新的JDK中你可以使用VarHandle::withInvokeExactBehavior来强制执行)。

通过将 VarHandle set 和 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);
}    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐