如何创建VarHandle实例来访问动态大小数组的元素(在外部函数和内存 API 的上下文中)?
package org.example;
import java.lang.foreign.*;
import java.lang.invoke.VarHandle;
public class ArrayVarHandle {
static final StructLayout coordinateLayout = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
static final SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(1, coordinateLayout);
static final VarHandle xInArrayVarHandle = arrayLayout.varHandle(
MemoryLayout.PathElement.sequenceElement(),
MemoryLayout.PathElement.groupElement("x")
);
public static void main(String[] args) {
try (var arena = Arena.ofConfined()) {
int count = 10;
var array = arena.allocate(coordinateLayout, count);
setXValues(array, count);
}
}
static void setXValues(MemorySegment array, int count) {
for (int i = 0; i < count; i++)
xInArrayVarHandle.set(array, 0, i, 100);
}
}
此代码失败,但出现以下异常:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)
显然,它检查布局的边界arrayLayout
。它用(第一个参数)声明elementCount = 1
。
如果用 来声明elementCount = 999999
,错误就会改变:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ address: 0x6000014b8140, byteSize: 80 }; new offset = 0; new length = 7999992
at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)
因此,它根据内存段的大小检查布局的大小,并再次失败。
是否可以创建没有固定大小的数组/序列布局?或者VarHandle
以其他方式创建?
在上面的例子中,count
有一个固定值。但在实际应用中,计数在编译时是未知的。目标是只创建VarHandle
一次实例,而不是在每次调用方法时都创建。
听起来你不是在寻找
SequenceLayout
(正如你所观察到的,它旨在用于固定大小的数组),而是在寻找arrayElementVarHandle
,它旨在用于可变长度的数组。然后你会用 进行分配arena.allocate(coordinateLayout, count)
。本文档部分已明确解决了这个问题。