动态数据列表类的不变式
重点:形式化定义转换成 checkInvariants
代码
形式化定义
txt
Invariant:
(1) data != null
(2) capacity > 0
(3) 0 <= size <= capacity
(4) ∀ i ∈ [0, size): data[i] != null
(5) ∀ i ∈ [size, capacity): data[i] == null
(6) capacity 仅通过 resize() 成倍增长
checkInvariants
源码
java
public void checkInvariants() {
// --- 1. 容量与大小约束检查 ---
// C1: 容量必须大于 0
if (capacity <= 0) {
throw new AssertionError("Invariant Broken: Capacity must be positive (capacity=" + capacity + ")");
}
// C2: Size 必须在 [0, capacity] 范围内
if (size < 0 || size > capacity) {
throw new AssertionError("Invariant Broken: Size must be between 0 and capacity (size=" + size + ", capacity=" + capacity + ")");
}
// --- 2. 数组和数据完整性检查 ---
// D1: 底层数组必须存在
if (data == null) {
throw new AssertionError("Invariant Broken: Internal array 'data' must not be null.");
}
// D2: 数组的实际长度必须等于记录的 capacity
if (data.length != capacity) {
throw new AssertionError("Invariant Broken: data.length (" + data.length + ") does not match recorded capacity (" + capacity + ")");
}
// --- 3. 数据填充和空值约束检查 ---
// 验证有效数据范围 [0, size-1]
for (int i = 0; i < size; i++) {
// D3: 有效数据区域 [0, size-1] 不得包含 null
if (data[i] == null) {
// 根据您的 add 方法,data[i] 应该是非空的
throw new AssertionError("Invariant Broken: Element at index " + i + " must not be null (size=" + size + ")");
}
}
// 验证闲置空间范围 [size, capacity-1]
for (int j = size; j < capacity; j++) {
// D4: 闲置空间 [size, capacity-1] 必须为 null (防止内存泄漏)
if (data[j] != null) {
throw new AssertionError("Invariant Broken: Element at index " + j + " must be null to prevent memory leak (size=" + size + ", capacity=" + capacity + ")");
}
}
InternalIterator it = new InternalIterator();
int elementsFound = 0;
while(it.hasNext()) {
try {
it.next();
elementsFound++;
} catch (NoSuchElementException e) {
throw new AssertionError("Iterator failed unexpectedly near index " + elementsFound);
}
}
if (elementsFound != size) {
throw new AssertionError("Iterator found " + elementsFound + " elements, but size is " + size);
}
}
使用指南
- 整合代码: 将
checkInvariants()
方法添加到您的DArrayList
类定义中。 - 插入调用: 在每个修改数组状态的方法(
DArrayList
的add
和remove
以及私有方法resize
)的末尾调用this.checkInvariants();
。
通过这种方式,每次修改数组后,程序都会进行一次快速的自我验证,确保您的动态扩容和元素移动逻辑没有破坏任何核心不变式。