ZxdNoob
首页文章简历版本历史AI 向导

ZxdNoob

用心记录,认真生活

按 ⌘K 快速导航到任意页面按 ⌘I 打开 AI 向导(或访问 /agent)

导航

  • 首页
  • 简历
  • 版本历史
  • AI 向导

更多

  • GitHub
  • Sitemap

© 2026 ZxdNoob. All rights reserved.

Built with Next.js · Styled with Tailwind CSS

返回文章列表
2026年5月2日 00:12:002 分钟阅读

Java 基础 02:面向对象、集合框架与泛型(正确用上接口与算法复杂度)

初级必读:类/接口/抽象的分工、equals 与 hashCode 契约、List/Set/Map 选型、迭代与并发修改;泛型如何避免强制转换地狱。

  • Java
  • 集合
  • 泛型
  • 基础
AI 共读让 Noob 帮你提炼要点 / 答疑

本篇目标:你能为业务对象正确实现 equals/hashCode;能说明 ArrayList/HashMap 常见操作复杂度;能用泛型避免强转;能解释 fail-fast 与「可变对象作 key」的坑。


1. 知识点:接口 / 抽象类 / 组合#

机制何时用反模式
interface多种实现、对外契约接口膨胀成「上帝接口」
abstract class复用骨架,保留一步抽象深层继承树
组合「有一个」能力委托仅为复用代码而继承

学以致用:价格策略 interface Pricing { Money quote(Order o); },促销/会员各实现一类,上层只依赖接口。


2. 知识点:equals 与 hashCode 契约(逐项)#

对用作 HashMap/HashSet 元素的类型:

  1. 自反:x.equals(x)。
  2. 对称:x.equals(y) ⇒ y.equals(x)。
  3. 传递:相等关系传递。
  4. 一致:不变对象多次比较结果不变。
  5. 对 null 返回 false。
  6. hashCode 一致:若相等,则 hashCode 必须相同;反之不必。

实践:用 IDE 生成或 Java 16+ record(自动生成 equals/hashCode),并对值字段设置为 final。

反例(必须能讲清):

import java.util.*;

public class BadKey {
  String name;
  BadKey(String name) { this.name = name; }
  @Override public boolean equals(Object o) {
    return o instanceof BadKey b && Objects.equals(name, b.name);
  }
  @Override public int hashCode() { return Objects.hash(name); }

  public static void main(String[] args) {
    Map<BadKey, String> map = new HashMap<>();
    BadKey k = new BadKey("a");
    map.put(k, "v");
    k.name = "b";
    System.out.println(map.get(k)); // 可能 null:破坏了 hash 桶假设
  }
}

3. 知识点:List 选型#

实现get(i)尾部 add头插/中间插备注
ArrayListO(1) 摊销均摊 O(1)O(n)默认首选;内部数组扩容(通常 1.5×)
LinkedListO(n)O(1)O(1) 节点随机访问差;多数业务不如 ArrayList

学以致用:大量随机下标访问 → ArrayList;实现 LRU 常配合 LinkedHashMap 而非盲目 LinkedList。


4. 知识点:Map / Set#

类型有序性底层直觉
HashMap无序数组 + 链表/树
LinkedHashMap插入顺序额外双向链表
TreeMap键排序红黑树,O(log n)

HashMap.get 平均 O(1);TreeMap 需要 Comparable 或 Comparator。


5. 知识点:迭代与 fail-fast#

List<Integer> xs = new ArrayList<>(List.of(1, 2, 3));
for (Integer x : xs) {
  if (x == 2) xs.remove(x); // ConcurrentModificationException
}

正确姿势:用 Iterator.remove()、removeIf,或收集后再删。


6. 知识点:泛型与 PECS#

PECS:Producer Extends, Consumer Super。

  • 只读出 T:List<? extends T>
  • 只写入 T:List<? super T>

学以致用:工具方法拷贝:

public static <T> void copy(List<? extends T> src, List<? super T> dst) {
  for (T t : src) dst.add(t);
}

7. 知识点:Stream 初用(注意副作用)#

Map<String, Long> freq = words.stream()
    .collect(Collectors.groupingBy(w -> w, Collectors.counting()));

避免在 forEach 里修改外部可变集合 unless 清楚并发语义。


8. Lab:购物车#

  • record LineItem(ProductId id, int qty, Money price) {}
  • Map<ProductId, LineItem> lines;合并同款商品数量。
  • 覆盖 ProductId 的 equals/hashCode(或 record)。

9. 自测清单#

  1. 解释 ArrayList 扩容触发点与摊销意义。
  2. 为何「可变对象作 HashMap 键」危险?
  3. 写 static <T extends Comparable<T>> T max(List<T> xs) 空表抛 NoSuchElementException。
  4. fail-fast 与设计并发修改的关系?

下一篇:异常、NIO.2 与线程池入门。

相关阅读

基于内容相似度 + 标签/系列加权

  • 2026年5月2日 00:06:002 分钟Java 从基础到精通(初级 · 高级 · 专家路线)
    01

    Java 基础 01:平台、JDK、字节码与可维护的最小项目骨架

    写给初级工程师:JVM/JRE/JDK 分工、源码到字节码的路径、classpath 与模块的基础心智;用 Maven 或 Gradle 搭一个最小可测试骨架。

    • Java
    • JVM
    • 基础
  • 2026年5月2日 00:18:002 分钟Java 从基础到精通(初级 · 高级 · 专家路线)
    02

    Java 基础 03:异常体系、try-with-resources、IO/NIO.2 入门与并发初探

    初级收尾篇:受检/非受检异常取舍、异常链与日志;现代 IO 用法;线程与 synchronized 的最小正确用法,为进阶 JUC 铺路。

    • Java
    • 异常
    • IO
  • 2026年5月2日 00:24:002 分钟Java 从基础到精通(初级 · 高级 · 专家路线)
    03

    Java 进阶 01:JUC、线程池、CompletableFuture 与异步组合实战

    写给高级工程师:happens-before 直觉、Lock 与原子类、ExecutorService 参数含义、超时/取消/组合异步;常见踩坑与背压入门。

    • Java
    • 并发
    • JUC
  • 2026年5月2日 00:00:002 分钟Java 从基础到精通(初级 · 高级 · 专家路线)
    04

    Java 路线 00:从初级到专家的三层能力模型、学习顺序与全系列索引

    面向初级、高级与资深/专家 Java 工程师的分层路线:每层该学什么、如何验收、与本系列各篇的对应关系;附统一练习模板与进阶节奏。

    • Java
    • 学习路线
    • 方法论
返回文章列表

目录

9
  1. 1. 知识点:接口 / 抽象类 / 组合
  2. 2. 知识点:`equals` 与 `hashCode` 契约(逐项)
  3. 3. 知识点:List 选型
  4. 4. 知识点:Map / Set
  5. 5. 知识点:迭代与 fail-fast
  6. 6. 知识点:泛型与 PECS
  7. 7. 知识点:`Stream` 初用(注意副作用)
  8. 8. Lab:购物车
  9. 9. 自测清单
进入沉浸式阅读