0Pricing
Java Academy · 课时

布局与结构体

描述原生内存布局

布局与结构体 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

描述本地内存

本地数据很少只有一个值。C 使用结构体、数组和联合体。FFM 使用内存布局来表示这些形状,从而安全地读写结构化的本地内存。

布局类型体系

布局类型构成了一个小型层次结构:

  • ValueLayout:基本类型(整数、长整数、双精度浮点数、地址)
  • SequenceLayout:由某种布局构成的固定大小数组
  • StructLayout:字段按顺序排列
  • UnionLayout:字段相互重叠

值布局

最简单的布局是内置值布局。它们包含大小、对齐方式和字节序信息。

import java.lang.foreign.ValueLayout;

public class Main {
    public static void main(String[] args) {
        System.out.println("int size: " + ValueLayout.JAVA_INT.byteSize());
        System.out.println("double size: " + ValueLayout.JAVA_DOUBLE.byteSize());
    }
}

定义结构体

使用 MemoryLayout.structLayout(...) 表示 C 结构体,并通过 withName 为每个字段命名。考虑下面的 C 代码:struct Point { int x; int y; }。

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        StructLayout point = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("x"),
            ValueLayout.JAVA_INT.withName("y"));
        System.out.println("Point size: " + point.byteSize());
    }
}

字段的 VarHandle

要读取或写入命名字段,请使用路径表达式派生一个 VarHandle。groupElement("x") 会按名称选择字段。

import java.lang.foreign.*;
import java.lang.invoke.VarHandle;

public class Main {
    public static void main(String[] args) {
        StructLayout point = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("x"),
            ValueLayout.JAVA_INT.withName("y"));
        VarHandle xHandle = point.varHandle(
            MemoryLayout.PathElement.groupElement("x"));
        System.out.println("Built VarHandle for x: " + xHandle);
    }
}

读写结构体

分配一个大小与布局匹配的内存段,然后使用 VarHandle 设置和获取字段。这与填充 C 结构体的方式相似。

import java.lang.foreign.*;
import java.lang.invoke.VarHandle;

public class Main {
    public static void main(String[] args) {
        StructLayout point = MemoryLayout.structLayout(
            ValueLayout.JAVA_INT.withName("x"),
            ValueLayout.JAVA_INT.withName("y"));
        VarHandle xh = point.varHandle(MemoryLayout.PathElement.groupElement("x"));
        VarHandle yh = point.varHandle(MemoryLayout.PathElement.groupElement("y"));
        try (Arena arena = Arena.ofConfined()) {
            MemorySegment p = arena.allocate(point);
            xh.set(p, 0L, 3);
            yh.set(p, 0L, 4);
            System.out.println("Point = (" + xh.get(p, 0L) + ", " + yh.get(p, 0L) + ")");
        }
    }
}

填充与对齐

C 编译器会插入填充,以确保字段正确对齐。FFM不会自动添加填充,因此必须加入 MemoryLayout.paddingLayout(n),以便与 C 布局完全匹配。

对齐方式错误会破坏间隔之后的每一个字段。

显式填充示例

对于 struct { char c; int n; },整数必须按 4 字节对齐,因此 char 后面要跟随 3 个填充字节。

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        StructLayout s = MemoryLayout.structLayout(
            ValueLayout.JAVA_BYTE.withName("c"),
            MemoryLayout.paddingLayout(3),
            ValueLayout.JAVA_INT.withName("n"));
        System.out.println("Aligned struct size: " + s.byteSize());
    }
}

序列布局

SequenceLayout 用于描述数组。MemoryLayout.sequenceLayout(count, element) 可以表示例如包含 10 个双精度浮点数的数组。

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        SequenceLayout arr = MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_DOUBLE);
        System.out.println("Array bytes: " + arr.byteSize());
    }
}

嵌套布局

布局可以组合。结构体可以包含序列,序列也可以包含结构体。使用 sequenceElement() 和 groupElement(name) 这样的路径表达式,可以深入访问嵌套数据。

这样就能处理任意复杂程度的真实 C 数据结构。

偏移量与切片

您可以通过路径查询字段的 byteOffset,并使用 segment.asSlice(offset, size) 获取子内存段;这对于将结构体中的某个字段传递给本地函数很有用。

快速检查

回想一下,结构体中常见的陷阱是什么。

总结

您已经学会了描述本地数据:

  • 布局类型体系:ValueLayout、SequenceLayout、StructLayout、UnionLayout
  • 使用 withName 为字段命名;通过 VarHandle 和路径元素访问字段
  • 添加显式的 paddingLayout,以确保正确对齐
  • 组合嵌套布局,并使用 asSlice 创建切片

至此,外部函数与内存 API 课程就完成了。

常见问题解答

「布局与结构体」课时是免费的吗?

是的 — 「布局与结构体」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「布局与结构体」这节课中我会学到什么?

描述原生内存布局 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「布局与结构体」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 为什么选择 FFM 而不是 JNI
  2. MemorySegment 与 Arena
  3. 下调用句柄
  4. 布局与结构体
← 返回 Java Academy