数组工具类(ArrayUtil)

基本信息

属性 值
类 com.falsepattern.chunk.api.ArrayUtil
修饰 @ApiStatus.NonExtendable(不可被继承)
方法 11 个静态 copyArray 重载(10 个基本/泛型数组 + 1 个 NibbleArray)
源码行数 184 行,其中 11 个方法体各 6~12 行,全部形如同一段代码的复制

@SuppressWarnings("DuplicatedCode") 明确标注了这 11 个重载是有意复制的(Java 无法用泛型数组统一基本类型)。

统一的复制契约

前 10 个重载逐字相同的控制流:

if (src == null)                    return null;          // null 透传
if (dst == null || src.length != dst.length)
                                      return Arrays.copyOf(src, src.length);  // 新分配
System.arraycopy(src, 0, dst, 0, src.length);
return dst;                                              // 原地传输,复用 dst

每个方法都带同样的 @Contract:

@Contract(value = "null, _ -> null;" +
                  "!null, null -> new;", mutates = "param2")

⚠️ @Contract 与实现不完全一致:Arrays.copyOf 分支也在 src.length != dst.length 时触发(即 dst 非 null 但长度不同时),而契约只声明了 !null, null -> new。这是 Eclipse 契约表达能力有限,非源码错误。

返回 null 的唯一情形是 src == null——dst 为 null 或长度不符都返回新数组。因此调用方不能靠返回 null 判断"目标不可用",只能靠"源不可用"。

10 个基本类型 / 泛型重载

# 签名
1 boolean[] copyArray(boolean[] src, boolean[] dst)
2 byte[] copyArray(byte[] src, byte[] dst)
3 char[] copyArray(char[] src, char[] dst)
4 short[] copyArray(short[] src, short[] dst)
5 int[] copyArray(int[] src, int[] dst)
6 long[] copyArray(long[] src, long[] dst)
7 float[] copyArray(float[] src, float[] dst)
8 double[] copyArray(double[] src, double[] dst)
9 <T> T[] copyArray(T[] src, T[] dst)

(上表 9 项为基本类型与泛型重载;第 10 个基本类型重载之外,第 11 个是下节的 NibbleArray 特例。)

NibbleArray 特例

public static NibbleArray copyArray(NibbleArray srcArray, NibbleArray dstArray) {
    if (srcArray == null) {
        return null;
    }
    if (dstArray == null) {
        return new NibbleArray(Arrays.copyOf(srcArray.data, srcArray.data.length), srcArray.depthBits);
    }
    dstArray.depthBits = srcArray.depthBits;
    dstArray.depthBitsPlusFour = srcArray.depthBitsPlusFour;
    dstArray.data = copyArray(srcArray.data, dstArray.data);
    return dstArray;
}

与其他 10 个重载的三处差异:

  1. 新分配的分支用 new NibbleArray(byte[], int),而非 Arrays.copyOf 单独返回——因为 NibbleArray 是包装类,必须返回包装类型
  2. 额外同步两个标量字段 depthBits 与 depthBitsPlusFour(半字节深度,通常为 4)
  3. 内部再调一次 copyArray(byte[], byte[]) 复用基本类型重载

⚠️ NibbleArray 的三个字段(data、depthBits、depthBitsPlusFour)都是非 public,直接赋值依赖 Access Transformer把它们公开化(见 Access Transformer)。没有 AT 的话这个方法无法编译。

⚠️ depthBitsPlusFour 被同步了,但 new NibbleArray(...) 分支只会从 depthBits 推算它——源码假定两者恒定关系(depthBits + 4)。

谁在用

全仓库 6 个调用点,全部在内置原版数据管理器的 clone 方法里(见 内置原版数据管理器):

调用点 数组类型 用途
BlockIDManager.cloneSubChunk byte[] × 2 LSB 数组 + MSB 数组
MetadataManager.cloneSubChunk NibbleArray metadata
SkylightManager.cloneSubChunk NibbleArray skylight(有 hasNoSky 分支)
BlocklightManager.cloneSubChunk NibbleArray blocklight
LightingManager.cloneChunk int[] heightMap
BiomeManager.cloneChunk byte[] biome 数组

即 ArrayUtil 的唯一用途是区块克隆时的数据搬运。经由 DataRegistry.cloneChunk / cloneSubChunk 两个 public 静态方法暴露给第三方(见 数据注册表)。

⚠️ BlocklightManager.cloneSubChunk 那一处把 ArrayUtil 的返回值赋给了 from 而非 to(源码笔误,详见 内置原版数据管理器)——ArrayUtil 本身行为正确,错在调用方。

char[] 与 float[] / double[] 三个重载在全仓库没有任何调用点,纯粹是为 API 完整性提供的。

相关条目