|
|
@@ -0,0 +1,309 @@
|
|
|
+# 2026-07-29 JavaSE 课后作业
|
|
|
+
|
|
|
+> **课程内容**:包装类(Wrapper Classes)、集合框架入门(Collection Framework)、ArrayList 底层实现、泛型(Generics)
|
|
|
+>
|
|
|
+> **涉及前序知识**:数组、面向对象、构造方法、包装类、ArrayList 基本使用、泛型基础
|
|
|
+>
|
|
|
+> **提交方式**:在 `提交\姓名\` 目录下创建对应的 Java 源文件
|
|
|
+>
|
|
|
+> **截止时间**:下次上课前
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📌 本次作业重要说明
|
|
|
+
|
|
|
+### 命名要求
|
|
|
+
|
|
|
+| 项目 | 要求 |
|
|
|
+|------|------|
|
|
|
+| **包名** | **必须按题目指定的包名创建**(全小写) |
|
|
|
+| **类名** | 自由命名,但需**见名知意** |
|
|
|
+| **测试类** | 建议命名为 `TestXxx` 或 `XxxTest` |
|
|
|
+| **文件名** | 必须与类名一致 |
|
|
|
+
|
|
|
+### 提交目录结构示例
|
|
|
+
|
|
|
+```
|
|
|
+提交\
|
|
|
+└─ 张三\
|
|
|
+ ├─ 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)](https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/ArrayList.java)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 第 1 题:ArrayList 构造方法源码注释分析 ⭐⭐⭐
|
|
|
+
|
|
|
+**包名**:`p1_arraylist_source`
|
|
|
+
|
|
|
+**知识点**:ArrayList 构造方法、默认容量、空数组与默认空数组的区别
|
|
|
+
|
|
|
+### 需求说明
|
|
|
+
|
|
|
+找到 `ArrayList.java` 中的以下三个构造方法,为**每一行代码**添加详细的中文注释(包括大括号和条件语句)。
|
|
|
+
|
|
|
+**要求**:
|
|
|
+- 注释必须包含该行代码的**作用说明**
|
|
|
+- 对于条件判断,需要说明什么条件下进入该分支
|
|
|
+- 对于方法调用,需要说明该方法的返回值或副作用
|
|
|
+- 对于你不认识的语法或 API,**必须上网查**并在注释中说明
|
|
|
+
|
|
|
+### 待注释的源码
|
|
|
+
|
|
|
+请复制以下三个构造方法到你的 Java 源文件中,并在每一行上方/后方添加注释:
|
|
|
+
|
|
|
+```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);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 构造方法 2:无参构造 ====================
|
|
|
+public ArrayList() {
|
|
|
+ this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 构造方法 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_ELEMENTDATA` 和 `DEFAULTCAPACITY_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 扩容机制、容量缩减、自动扩容、位运算
|
|
|
+
|
|
|
+### 需求说明
|
|
|
+
|
|
|
+为以下三个与容量 / 扩容相关的方法逐行添加中文注释。
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== trimToSize() - 缩减容量 ====================
|
|
|
+public void trimToSize() {
|
|
|
+ modCount++;
|
|
|
+ if (size < elementData.length) {
|
|
|
+ elementData = (size == 0)
|
|
|
+ ? EMPTY_ELEMENTDATA
|
|
|
+ : Arrays.copyOf(elementData, size);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== ensureCapacity(int) - 确保容量 ====================
|
|
|
+public void ensureCapacity(int minCapacity) {
|
|
|
+ if (minCapacity > elementData.length
|
|
|
+ && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
|
|
|
+ && minCapacity <= DEFAULT_CAPACITY)) {
|
|
|
+ modCount++;
|
|
|
+ grow(minCapacity);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 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 添加元素、删除元素、清空集合、数组拷贝
|
|
|
+
|
|
|
+### 需求说明
|
|
|
+
|
|
|
+为以下四个与元素操作相关的方法逐行添加中文注释。
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 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;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 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;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 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;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```java
|
|
|
+// ==================== 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` 方法?** 为什么要把参数 `elementData` 和 `s` 传进来,而不是直接在方法内访问成员变量?
|
|
|
+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` 测试所有方法
|
|
|
+
|
|
|
+**测试数据示例**:
|
|
|
+
|
|
|
+```java
|
|
|
+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 分(加分) | 功能完整性、代码质量、测试覆盖度 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 参考资料
|
|
|
+
|
|
|
+- JDK 源码 `ArrayList.java`(位于 JDK 安装目录的 `src.zip` 中)
|
|
|
+- [OpenJDK ArrayList.java (JDK 21)](https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/ArrayList.java)
|
|
|
+- [Java ArrayList 官方文档](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ArrayList.html)
|
|
|
+- [System.arraycopy 方法详解](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/System.html#arraycopy(java.lang.Object,int,java.lang.Object,int,int))
|
|
|
+- [Java 泛型通配符详解](https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html)
|
|
|
+
|