2026年7月29日-作业.md 12 KB

2026-07-29 JavaSE 课后作业

课程内容:包装类(Wrapper Classes)、集合框架入门(Collection Framework)、ArrayList 底层实现、泛型(Generics)

涉及前序知识:数组、面向对象、构造方法、包装类、ArrayList 基本使用、泛型基础

提交方式:在 提交\姓名\ 目录下创建对应的 Java 源文件

截止时间:下次上课前


📌 本次作业重要说明

命名要求

项目 要求
包名 必须按题目指定的包名创建(全小写)
类名 自由命名,但需见名知意
测试类 建议命名为 TestXxxXxxTest
文件名 必须与类名一致

提交目录结构示例

提交\
└─ 张三\
    ├─ p1_arraylist_source\               ← 第 1~3 题的包
    │   ├── ArrayListSourceAnalysis.java  ← 源码注释分析(含所有方法)
    │   └── ArrayListSourceAnalysis.md    ← 思考题回答
    └─ p2_myarraylist\                    ← 第 4 题(选做)
        ├── MyArrayList.java              ← 手写简化版 ArrayList
        └── MyArrayListTest.java          ← 测试类

作业说明

本次作业的目的是让你深入阅读 ArrayList 的源码,理解其底层实现机制。请根据题目要求找到 JDK 中 ArrayList.java 的源码,对指定方法进行逐行注释分析。

📌 如何找到 ArrayList 源码?

  1. 在 JDK 安装目录下找到 src.zip,解压后进入 java.base/java/util/ArrayList.java
  2. 或者使用 IDE(IntelliJ IDEA / Eclipse)直接打开 ArrayList 类,点击「Download Sources」
  3. 或者查阅 OpenJDK 在线源码:ArrayList.java (JDK 21)

第 1 题:ArrayList 构造方法源码注释分析 ⭐⭐⭐

包名p1_arraylist_source

知识点:ArrayList 构造方法、默认容量、空数组与默认空数组的区别

需求说明

找到 ArrayList.java 中的以下三个构造方法,为每一行代码添加详细的中文注释(包括大括号和条件语句)。

要求

  • 注释必须包含该行代码的作用说明
  • 对于条件判断,需要说明什么条件下进入该分支
  • 对于方法调用,需要说明该方法的返回值或副作用
  • 对于你不认识的语法或 API,必须上网查并在注释中说明

待注释的源码

请复制以下三个构造方法到你的 Java 源文件中,并在每一行上方/后方添加注释:

// ==================== 构造方法 1:指定初始容量 ====================
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
    }
}
// ==================== 构造方法 2:无参构造 ====================
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// ==================== 构造方法 3:传入集合 ====================
public ArrayList(Collection<? extends E> c) {
    Object[] a = c.toArray();
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        elementData = EMPTY_ELEMENTDATA;
    }
}

需要深入研究并回答的问题

  1. EMPTY_ELEMENTDATADEFAULTCAPACITY_EMPTY_ELEMENTDATA 都是空数组,为什么要有两个?有什么区别?
  2. 无参构造中,为什么 elementData 不直接 new Object[10],而是先指向一个空数组?
  3. 构造方法 3 中为什么要判断 c.getClass() == ArrayList.class?如果不判断直接使用 Arrays.copyOf(a, size, Object[].class) 会有什么问题?
  4. Collection<? extends E> c 中的 ? extends E 是什么意思?有什么用?

第 2 题:ArrayList 扩容相关方法源码注释分析 ⭐⭐⭐⭐

包名p1_arraylist_source(与第 1 题同一个包)

知识点:ArrayList 扩容机制、容量缩减、自动扩容、位运算

需求说明

为以下三个与容量 / 扩容相关的方法逐行添加中文注释。

// ==================== trimToSize() - 缩减容量 ====================
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}
// ==================== ensureCapacity(int) - 确保容量 ====================
public void ensureCapacity(int minCapacity) {
    if (minCapacity > elementData.length
        && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
             && minCapacity <= DEFAULT_CAPACITY)) {
        modCount++;
        grow(minCapacity);
    }
}
// ==================== grow(int) - 扩容核心方法 ====================
private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity,
                oldCapacity >> 1);
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}

需要深入研究并回答的问题

  1. modCount 是什么? 它在 ArrayList 中起什么作用?(提示:fail-fast 机制)
  2. ArraysSupport.newLength(int oldLength, int minGrowth, int prefGrowth) 这个方法是干什么的?三个参数分别是什么含义?它的返回值是如何计算的?
  3. oldCapacity >> 1 计算结果是多少?为什么扩容时选择"旧容量的一半"作为 preferred growth?
  4. ensureCapacity 方法中的两个条件为什么要用 && 连接? 什么情况下即使 minCapacity > elementData.length 也不会立即扩容?
  5. trimToSize() 中的三目运算符 (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size) 分别对应什么场景?
  6. grow() 方法中的 if-else 分支:什么情况下进入 if 分支?什么情况下进入 else 分支?

第 3 题:ArrayList 增删改核心方法源码注释分析 ⭐⭐⭐⭐⭐

包名p1_arraylist_source(与第 1 题同一个包)

知识点:ArrayList 添加元素、删除元素、清空集合、数组拷贝

需求说明

为以下四个与元素操作相关的方法逐行添加中文注释。

// ==================== add(E, Object[], int) - 内部添加辅助方法 ====================
private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
}
// ==================== remove(int) - 按索引删除元素 ====================
public E remove(int index) {
    Objects.checkIndex(index, size);
    final Object[] es = elementData;

    @SuppressWarnings("unchecked")
    E oldValue = (E) es[index];
    fastRemove(es, index);

    return oldValue;
}
// ==================== fastRemove(Object[], int) - 快速删除(不检查边界) ====================
private void fastRemove(Object[] es, int i) {
    modCount++;
    final int newSize;
    if ((newSize = size - 1) > i)
        System.arraycopy(es, i + 1, es, i, newSize - i);
    es[size = newSize] = null;
}
// ==================== clear() - 清空集合 ====================
public void clear() {
    modCount++;
    final Object[] es = elementData;
    for (int to = size, i = size = 0; i < to; i++)
        es[i] = null;
}

需要深入研究并回答的问题

  1. add(E e) 的返回类型是 boolean,但始终返回 true,为什么还要设计成有返回值?
  2. add(E e, Object[] elementData, int s) 为什么被设计成 private 方法? 为什么要把参数 elementDatas 传进来,而不是直接在方法内访问成员变量?
  3. Objects.checkIndex(index, size) 是做什么的?如果 index 越界会怎样?
  4. @SuppressWarnings("unchecked") 是什么作用?为什么这里需要加这个注解?
  5. fastRemove 方法中的 System.arraycopy 是做什么的?参数 es, i + 1, es, i, newSize - i 分别代表什么?
  6. fastRemove 删除元素后,为什么要将最后一个位置设为 null(即 es[size = newSize] = null;
  7. clear() 方法的 for 循环中,为什么 i < to 的条件不直接写 i < size?为什么要先把 size 赋值给 to,然后设置 size = 0
  8. clear() 方法遍历置 null 和直接 elementData = EMPTY_ELEMENTDATA 有什么区别? 哪种方式更好?为什么 JDK 选择了前者?

第 4 题:手写简化版 MyArrayList(选做 / 加分题)⭐⭐⭐⭐⭐

包名p2_myarraylist

知识点:综合运用泛型、数组操作、扩容机制

需求说明

基于你对 ArrayList 源码的理解,手写一个简化版的 MyArrayList<E> 类,实现以下方法:

方法 说明
MyArrayList() 无参构造,默认容量 10
MyArrayList(int initialCapacity) 指定初始容量
boolean add(E e) 添加元素(自动扩容)
E get(int index) 获取元素(检查越界)
E set(int index, E element) 修改元素
E remove(int index) 删除元素(返回被删除的元素)
int size() 返回元素个数
boolean isEmpty() 判断是否为空
void clear() 清空所有元素
String toString() 返回格式如 [元素1, 元素2, ...]

要求

  1. 必须使用泛型MyArrayList<E>
  2. 底层使用 Object[] 存储数据
  3. 实现自动扩容机制(参考 JDK 的 1.5 倍扩容)
  4. 所有方法必须添加详细中文注释
  5. 编写测试类 MyArrayListTest 测试所有方法

测试数据示例

MyArrayList<String> list = new MyArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println(list);           // [Java, Python, C++]
System.out.println(list.size());    // 3
System.out.println(list.get(1));    // Python
list.set(1, "JavaScript");
list.remove(0);
System.out.println(list);           // [JavaScript, C++]
System.out.println(list.isEmpty()); // false
list.clear();
System.out.println(list.isEmpty()); // true

评分标准

题号 分值 评分维度
第 1 题 25 分 注释是否覆盖每一行、注释是否准确、思考题是否回答正确
第 2 题 30 分 注释深度(是否有查阅资料)、扩容机制理解是否正确、思考题回答质量
第 3 题 30 分 增删改方法注释是否完整、System.arraycopy 理解是否正确、思考题回答质量
第 4 题 15 分(加分) 功能完整性、代码质量、测试覆盖度

参考资料