集合 = 会自动伸缩、自带工具箱的对象容器——数组的三大痛点(定长、删插麻烦、没工具)它全包了。本章先看家族地图,后面逐站细逛。
7.1 集合概述
1. 为什么需要集合?——数组的三大痛点
2.7 学的数组很能干,但有三个先天短板:
int[] arr = new int[3]; // ① 长度定死:永远 3 格
arr[0] = 42;
// 来第 4 个数?只能 new 个新数组整体搬家
// 删 arr[1]?自己写循环把后面的整体前挪
// 查 42 在不在?自己写 for 循环挨个比
| 痛点 | 数组的表现 | 集合的解法 |
|---|---|---|
| 长度定死 | new int[3] 永远 3 格,扩容要自己搬家 |
add() 自动伸、remove() 自动缩 |
| 删插麻烦 | 删中间一个,后面全体挪窝,手写循环 | remove(下标) 一行,挪窝它来干 |
| 没有工具 | 查找、去重全自己写 | contains 查、size 数,Set 自动去重 |
类比:数组是"定长的格子间",集合是"能扩建的宿舍楼"——住几个人随时改,还配了物业(现成方法)。
2. 集合是什么?
集合(Collection)就是 Java 官方提供的「存对象的容器」——底层也是数组或链表,但把脏活累活全封装好了,你只管调方法。
和数组最大的差别一句话:数组管"存",集合管"存 + 活"。
3. 集合家族地图(本节先认站名)
集合
├── Collection 体系(一次存一个)
│ ├── List:有序、可重复 —— 像排队,有编号
│ │ └── ArrayList ★ 本章主站(用得最多)
│ └── Set:不重复 —— 像点名册
│ └── HashSet(去重看 hashCode,4.5 的钩子在这收网)
└── Map 体系(成对存:键 → 值)
└── HashMap —— 像字典,查字用页码
| 体系 | 特点 | 类比 | 代表 |
|---|---|---|---|
| List | 有序、可重复、有下标 | 排队 | ArrayList |
| Set | 不重复(可能无序) | 点名册 | HashSet |
| Map | 键值成对,键唯一 | 字典 | HashMap |
三大站点的细节后面每节细讲。现在只需要记住:要"排队存东西"找 List/ArrayList;要"不重复"找 Set;要"按名字查东西"找 Map。
4. 先上手:第一个 ArrayList 程序
import java.util.ArrayList;
public class Demo01 {
public static void main(String[] args) {
// 创建一个只能装字符串的集合
ArrayList<String> list = new ArrayList<>();
// ① 加
list.add("波仔");
list.add("墨池");
list.add("AI");
System.out.println(list); // [波仔, 墨池, AI] —— 直接打印!
// ② 查
System.out.println(list.get(0)); // 波仔 —— 下标从 0 开始,和数组一样
System.out.println(list.size()); // 3
System.out.println(list.contains("墨池")); // true
// ③ 删
list.remove("AI");
System.out.println(list.size()); // 2 —— 长度自己缩了
}
}
五个最常用的方法,先混个脸熟(后面节细讲):
| 方法 | 作用 | 对应数组的…… |
|---|---|---|
add(e) |
加到末尾 | arr[下标] = e(但不用管下标) |
get(i) |
取第 i 个 | arr[i] |
size() |
数元素个数 | arr.length(注意是方法带括号) |
remove(i 或 e) |
删除 | 自己写循环挪窝 |
contains(e) |
查在不在 | 自己写 for 循环 |
5. 泛型 <String>:先会认
ArrayList<String> 尖括号里的类型叫泛型——意思是"这个集合只装这一类东西":
ArrayList<String> names = new ArrayList<>(); // 只装字符串
names.add("波仔"); // ✓
names.add(42); // ✗ 编译报错——类型不对,当场拦下
两个规矩:
- 泛型只能写引用类型,不能写基本类型:
ArrayList<int>✗ →ArrayList<Integer>✓ - 右边的
<>可以空着(钻石写法),类型自动推断
不写泛型的集合什么都能塞(默认装 Object),取出来还得强转(4.4 的 ClassCastException 风险区)。写了泛型,塞错类型编译就报错——把错误拦在运行前,这是 5 章以来一贯的思想:能编译期发现的问题,绝不留到运行期。
6. 一条铁规矩:集合只能装对象
list.add(42) 明明塞的是数字,为什么能进 ArrayList<Integer>?
自动装箱(6.1 的第一道门在此上岗):42 被悄悄包装成 Integer 对象再入箱。
ArrayList<Integer> nums = new ArrayList<>();
nums.add(42); // 42 → Integer.valueOf(42) 自动装箱
int x = nums.get(0); // Integer → 42 自动拆箱
System.out.println(nums.get(0) + 1); // 43 —— 拆箱后能算术
6.1 讲过的两个坑在集合里照样成立:缓存池(两个集合里的 127 用 == 是 true,128 是 false——比内容用 equals);null 拆箱(集合里存了 null,取出赋给 int 直接 NPE)。
7. 集合 vs 数组:什么时候用谁?
| 数组 | 集合 | |
|---|---|---|
| 长度 | 固定 | 自动伸缩 |
| 能装什么 | 基本类型 + 对象都行 | 只能对象 |
| 效率 | 存取最快的裸容器 | 略有封装开销(可忽略) |
| 工具 | 无,自己写 | add/remove/contains 全套 |
| 使用场景 | 元素个数固定(如扑克 52 张) | 个数不定(如用户列表) |
经验法则:拿不准就用集合——效率差距在日常场景里感觉不到,灵活性的差距立竿见影。
8. 常见误区
编译报错。泛型只能写引用类型,基本类型要用包装类:int→Integer、double→Double(6.1 的 8 大对照表派上用场)。
没有 length 属性。数组用 arr.length(属性),集合用 list.size()(方法带括号)——新手最常混的一对。
集合存的是对象的引用(地址)——和数组存对象一个道理(3.3 方法传对象)。改了对象,集合里"跟着变",不是复制了多份。
remove(1) 删的是下标 1 的元素;想删"值为 1 的 Integer"要 remove(Integer.valueOf(1))。Integer 重载的这个歧义后面细节节再收拾,先记住有这坑。
System.out.println(list) 直接就能打印出 [a, b, c]——集合重写了 toString(4.5 学的知识),不用自己遍历着拼。
9. 动手试一试(30 秒实验)
新建 Demo01(记得 import java.util.ArrayList;):
实验 1:add 三个名字后直接 System.out.println(list),看 [波仔, 墨池, AI] 格式——对比 4.5 里 类名@乱码,体会 toString 重写。
实验 2:ArrayList<Integer> nums = new ArrayList<>(); 后 nums.add(42),打印——42 是 int,怎么进的 Integer 集合?(自动装箱)
实验 3:写 ArrayList<int> bad = new ArrayList<>();——亲眼看编译报错,把 int 改成 Integer 后通过。
实验 4:remove 中间一个元素再打印——看后面元素自动前移,对比 2.7 手写挪窝的循环。
10. 自测一下
数组长度固定、集合自动伸缩。个数固定(扑克 52 张)用数组;个数不定(购物车商品)用集合。集合还自带工具方法。
泛型——声明只装 String。不写则默认装 Object,什么都能塞但取出要强转,容易 ClassCastException;写了泛型塞错编译就报错。
自动装箱(6.1):int 42 被 Integer.valueOf(42) 包装成对象再入箱。取出时自动拆箱。集合只能装对象,基本类型全靠这道门。
数组 arr.length(属性,不带括号);集合 list.size()(方法,带括号)。
List 有序可重复有下标——排队;Set 不重复——点名册;Map 键值对键唯一——字典。选型口诀:排队用 List、去重用 Set、按名查用 Map。
11. 下一步学什么
- ☑ 7.2 Collection接口 ✅ —— 已完成:点此复习 —— 家族总纲细读:接口=合同、六大通用方法、contains 底层 equals(4.5 规矩真踩痛处)、两种遍历上岗。
相关笔记
- 第六章 Java API/6.9 本章小结 ← 上一篇:API 章完结,本章正式进入"容器"世界
- 第二章 Java编程基础/2.7 数组:数组的痛点是本章的出发点
- 第六章 Java API/6.1 包装类:集合只能装对象 → 自动装箱上岗第一线
- 第四章 面向对象(下)/4.5 Object类:hashCode 搭伴规矩,HashSet 去重时收网