本文纲要
- 集合与数组的区别 ------ 对象数组初体验
- ArrayList的构造方法与添加方法
- ArrayList常用成员方法(增删改查)
- 集合存储字符串并遍历
- 集合存储学生对象并遍历
- 键盘录入学生信息到集合
- 集合删除元素的注意事项
- 集合数据筛选 ------ 方法返回新集合
集合与数组的区别 ------ 对象数组初体验
数组和集合都是Java中用来存储数据的容器,但它们有一个关键区别:数组长度固定,集合长度可变。
在正式学习集合之前,我们先看一个案例:用数组存储自定义的学生对象。
需求
将(张三,23)、(李四,24)、(王五,25)这三组数据封装为三个学生对象,存入数组,然后遍历数组打印学生信息。
思路分析
- 定义学生类 Student,封装姓名和年龄
- 创建长度为3的 Student 类型数组
- 创建三个学生对象
- 将学生对象存入数组
- 遍历数组,取出每个学生对象,调用 getName()、getAge() 输出信息
代码实现
Student 类(位于 com.wb.domain 包):
java
package com.wb.domain;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
测试类 TestObjectArray:
java
package com.wb.array;
import com.wb.domain.Student;
public class TestObjectArray {
public static void main(String[] args) {
// 2. 动态初始化长度为3的数组,类型为Student类型
Student[] arr = new Student[3];
// 3. 根据需求创建3个学生对象
Student stu1 = new Student("张三", 23);
Student stu2 = new Student("李四", 24);
Student stu3 = new Student("王五", 25);
// 4. 将学生对象存入数组
arr[0] = stu1;
arr[1] = stu2;
arr[2] = stu3;
// 5. 遍历数组,取出每一个学生对象
for (int i = 0; i < arr.length; i++) {
Student temp = arr[i];
System.out.println(temp.getName() + "..." + temp.getAge());
}
}
}
运行结果:
log
张三...23
李四...24
王五...25
数组的局限性
- 如果此时来了一个新学生"赵六",数组已经满了,无法添加
- 虽然可以手动创建新数组并复制旧数据,但非常麻烦
- 我们期望有一个"懂事"的容器,能自动扩容,这就是集合
集合与数组的对比
- 共同点:都是存储数据的容器
- 不同点:
- 数组长度固定,定义后不可改变
- 集合长度可变,可以自动扩容
- 应用场景:需要频繁增删数据时,优先使用集合
ArrayList的构造方法与添加方法
Java中集合类很多,基础入门我们先学习 ArrayList
它底层仍然是数组实现,但提供了自动扩容的能力
1 ) 创建ArrayList对象
构造方法:ArrayList(),创建一个初始容量为10的空列表。
使用泛型限制集合存储的数据类型,语法:ArrayList<数据类型> 变量名 = new ArrayList<>();
JDK 7 起,右侧尖括号可省略类型,自动推断。
java
import java.util.ArrayList;
public class Demo1ArrayList {
public static void main(String[] args) {
// 创建只存储字符串的集合
ArrayList<String> list = new ArrayList<>();
// 如果不加泛型,可以存储任意类型,但类型不安全,不推荐
}
}
2 ) 添加元素
ArrayList 提供了两个添加方法:
| 方法 | 说明 |
|---|---|
| boolean add(E e) | 将元素添加到列表末尾 |
| void add(int index, E element) | 将元素插入到指定索引位置(插队) |
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
list.add(0, "666"); // 在索引0处插入
System.out.println(list); // 输出:[666, 111, 222, 333, 444, 555]
注意:
如果插入时索引越界,会抛出 IndexOutOfBoundsException。
集合对象直接打印不会出现内存地址,而是显示元素内容(底层重写了 toString)。
ArrayList常用成员方法(增删改查)
ArrayList 提供了丰富的增删改查方法,常用如下:
| 方法 | 说明 |
|---|---|
| boolean add(E e) | 尾部添加元素 |
| void add(int index, E e) | 指定位置插入元素 |
| boolean remove(Object o) | 删除指定元素,返回是否成功 |
| E remove(int index) | 删除指定索引元素,返回被删除的元素 |
| E set(int index, E e) | 修改指定索引元素,返回被修改前的元素 |
| E get(int index) | 获取指定索引元素 |
| int size() | 返回集合中元素个数 |
演示代码(整合删除、修改、查询):
java
import java.util.ArrayList;
public class Demo2ArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
// 删除:根据元素删除
boolean b1 = list.remove("abc"); // 删除成功返回true
boolean b2 = list.remove("zzz"); // 不存在返回false
System.out.println(b1); // true
System.out.println(b2); // false
// 删除:根据索引删除
String removed = list.remove(0); // 删除索引0的元素,返回被删除的元素
System.out.println(removed); // 111
// 修改
String old = list.set(0, "666"); // 将索引0元素改为"666",返回旧值
System.out.println(old); // 222
// 查询
String s1 = list.get(0); // 获取索引0元素
String s2 = list.get(1);
System.out.println(s1); // 666
System.out.println(s2); // 333
// 获取集合大小
int size = list.size();
System.out.println(size); // 4
System.out.println(list); // [666, 333, 444, 555]
}
}
提示:除了 get 和 size 外,删除、修改方法的返回值通常不需要接收,直接调用即可。
集合存储字符串并遍历
遍历集合的关键是结合 size() 和 get(int index) 方法,格式与遍历数组非常相似。
需求:创建存储字符串的集合,存入3个字符串,遍历打印。
代码实现:
java
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
// 通用遍历格式
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
}
}
遍历快捷键:在IDEA中输入 list.fori 回车,可快速生成循环骨架。
集合存储学生对象并遍历
当集合存储自定义对象时,遍历取出的是对象引用,需要调用对象方法才能获取具体信息。
需求:创建存储 Student 对象的集合,存入3个学生,遍历打印学生姓名和年龄。
代码实现:
java
import com.wb.domain.Student;
import java.util.ArrayList;
public class Test2 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
Student stu1 = new Student("张三1", 23);
Student stu2 = new Student("张三2", 23);
Student stu3 = new Student("张三3", 23);
list.add(stu1);
list.add(stu2);
list.add(stu3);
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
}
注意:如果直接打印 stu,输出的是对象地址,必须通过 getName() 等方法获取属性值。
键盘录入学生信息到集合
将之前手动创建的学生数据改为从键盘录入,使程序更灵活。
需求:键盘录入3个学生的姓名和年龄,封装成对象存入集合,遍历集合输出信息。
关键点:
使用 Scanner 接收键盘输入
为避免 nextLine() 与 nextInt() 混用导致的问题,这里使用 next() 接收字符串
将录入及封装逻辑抽取为方法 getStudent(),提高复用性
代码实现:
java
import com.wb.domain.Student;
import java.util.ArrayList;
import java.util.Scanner;
public class Test3 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
Student stu1 = getStudent();
Student stu2 = getStudent();
Student stu3 = getStudent();
list.add(stu1);
list.add(stu2);
list.add(stu3);
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
public static Student getStudent() {
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
System.out.println("请输入学生年龄:");
int age = sc.nextInt();
return new Student(name, age);
}
}
运行示例:
log
请输入学生姓名:
张三
请输入学生年龄:
23
请输入学生姓名:
李四
请输入学生年龄:
24
请输入学生姓名:
王五
请输入学生年龄:
25
张三...23
李四...24
王五...25
集合删除元素的注意事项
删除集合中的元素时,如果使用 remove(Object o) 方法,它只会删除第一个匹配的元素。
若要删除所有匹配的元素,必须遍历集合,并采用索引删除的方式,同时注意索引回退问题。
需求:删除集合中所有 "test" 字符串,集合初始元素为 "test", "张三", "李四", "test", "test"
错误做法:直接 list.remove("test") 只删除了第一个 "test"
正确做法:遍历时用索引删除,并在删除后执行 i--,防止漏掉连续的元素
删除过程图解
假设集合变化如下:
#mermaid-svg-xDcsvkn1sR10qWC9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xDcsvkn1sR10qWC9 .error-icon{fill:#552222;}#mermaid-svg-xDcsvkn1sR10qWC9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xDcsvkn1sR10qWC9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xDcsvkn1sR10qWC9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xDcsvkn1sR10qWC9 .marker.cross{stroke:#333333;}#mermaid-svg-xDcsvkn1sR10qWC9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xDcsvkn1sR10qWC9 p{margin:0;}#mermaid-svg-xDcsvkn1sR10qWC9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster-label text{fill:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster-label span{color:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster-label span p{background-color:transparent;}#mermaid-svg-xDcsvkn1sR10qWC9 .label text,#mermaid-svg-xDcsvkn1sR10qWC9 span{fill:#333;color:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 .node rect,#mermaid-svg-xDcsvkn1sR10qWC9 .node circle,#mermaid-svg-xDcsvkn1sR10qWC9 .node ellipse,#mermaid-svg-xDcsvkn1sR10qWC9 .node polygon,#mermaid-svg-xDcsvkn1sR10qWC9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xDcsvkn1sR10qWC9 .rough-node .label text,#mermaid-svg-xDcsvkn1sR10qWC9 .node .label text,#mermaid-svg-xDcsvkn1sR10qWC9 .image-shape .label,#mermaid-svg-xDcsvkn1sR10qWC9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xDcsvkn1sR10qWC9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xDcsvkn1sR10qWC9 .rough-node .label,#mermaid-svg-xDcsvkn1sR10qWC9 .node .label,#mermaid-svg-xDcsvkn1sR10qWC9 .image-shape .label,#mermaid-svg-xDcsvkn1sR10qWC9 .icon-shape .label{text-align:center;}#mermaid-svg-xDcsvkn1sR10qWC9 .node.clickable{cursor:pointer;}#mermaid-svg-xDcsvkn1sR10qWC9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xDcsvkn1sR10qWC9 .arrowheadPath{fill:#333333;}#mermaid-svg-xDcsvkn1sR10qWC9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xDcsvkn1sR10qWC9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xDcsvkn1sR10qWC9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xDcsvkn1sR10qWC9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xDcsvkn1sR10qWC9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xDcsvkn1sR10qWC9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster text{fill:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 .cluster span{color:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xDcsvkn1sR10qWC9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xDcsvkn1sR10qWC9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xDcsvkn1sR10qWC9 .icon-shape,#mermaid-svg-xDcsvkn1sR10qWC9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xDcsvkn1sR10qWC9 .icon-shape p,#mermaid-svg-xDcsvkn1sR10qWC9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xDcsvkn1sR10qWC9 .icon-shape .label rect,#mermaid-svg-xDcsvkn1sR10qWC9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xDcsvkn1sR10qWC9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xDcsvkn1sR10qWC9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xDcsvkn1sR10qWC9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
开始遍历 i=0
list.get i 是否为test?
list.remove i
i--
i++
i < list.size?
结束
为什么需要 i--?
删除当前元素后,后面所有元素会向前移动一位,如果直接 i++,就会跳过原本下一个位置的元素。
先 i-- 再 i++(循环自带 i++),相当于指针原地不动,重新检查当前位置的新元素,确保不遗漏。
代码实现:
java
import java.util.ArrayList;
public class Test4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("test");
list.add("张三");
list.add("李四");
list.add("test");
list.add("test");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
// 常量.equals(变量) 可避免空指针异常
if ("test".equals(s)) {
list.remove(i);
i--; // 关键:回退索引
}
}
System.out.println(list); // 输出:[张三, 李四]
}
}
最佳实践:字符串比较时,建议用常量调用 equals,如 "test".equals(s),避免 null 引发空指针异常。
集合数据筛选 ------ 方法返回新集合
本节演示如何编写一个方法,接收集合并根据条件筛选出部分元素返回新集合
需求:定义一个方法,接收一个 ArrayList<Student> 集合,将年龄低于18的学生对象筛选出来,存入新集合并返回
实现步骤
- 定义方法
getList,参数为ArrayList<Student>,返回值也为ArrayList<Student> - 方法内部创建新集合
newList - 遍历原集合,获取每个学生对象的年龄
- 判断年龄是否小于18,若满足则添加到
newList - 返回新集合
代码实现:
java
import com.wb.domain.Student;
import java.util.ArrayList;
public class Test5 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三1", 10));
list.add(new Student("张三2", 10));
list.add(new Student("张三3", 20));
ArrayList<Student> newList = getList(list);
for (int i = 0; i < newList.size(); i++) {
Student stu = newList.get(i);
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
public static ArrayList<Student> getList(ArrayList<Student> list) {
ArrayList<Student> newList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
if (stu.getAge() < 18) {
newList.add(stu);
}
}
return newList;
}
}
运行结果:
log
张三1...10
张三2...10
要点:
方法的形参和返回值可以是集合类型,调用时传递对应集合对象即可
这种"筛选并返回新集合"的模式在实际开发中非常常见,它为后续学习流式操作打下了基础
总结
通过本文,我们从对象数组入手,体会了数组的局限性,进而引入了 ArrayList 集合
学习了集合的构造、增删改查、遍历、键盘录入、删除注意事项以及筛选操作
掌握了这些基础,你就已经能够利用集合解决许多动态数据存储的问题了
在后续的学习中,还会接触到更多高级的集合类,但万变不离其宗,理解好 ArrayList 是第一步