ArrayList 的 remove(int) 和 remove(Object) 因重载导致行为歧义:remove(0) 删除索引0元素而非内容为0的对象;删对象必须传引用类型且 Student 重写 equals()/hashCode();遍历时删除须用 Iterator.remove() 或倒序 for;contains() 返回 false 是因未重写 equals() 导致地址比较;性能瓶颈在 O(n) 遍历操作,高频查询宜用 Map 辅助;成绩等字段应使用 Integer 而非 int 以区分“未录入”和“0分”。

为什么 ArrayList 的 remove(int) 和 remove(Object) 总是删错数据
因为同名重载函数行为完全不同,但编译器不报错,运行时才出问题。比如你本想删内容为 "张三" 的学生,却写了 list.remove(0) —— 看似像删第一个,实际是调用了按索引删除的版本;反过来,如果传了个 int 类型变量想删对象,也会被自动装箱成 Integer,结果还是走索引删除。
- 删元素内容:必须确保参数类型是
String、Student这类引用类型,且Student类重写了equals()和hashCode() - 删指定位置:用
remove(int index),但要注意下标越界会抛IndexOutOfBoundsException - 遍历时删除:绝不能用普通 for 循环配合
remove(),否则会跳过下一个元素;改用Iterator.remove()或倒序 for
学生成绩查重时,contains() 为啥总返回 false
ArrayList 默认用 Object.equals() 判断相等,而没重写 equals() 的 Student 类,比较的是内存地址,两个字段一模一样的对象也视为不相等。
- 必须在
Student类里重写equals()(至少比对id或name),同时补上hashCode() - 别只重写
equals()忘了hashCode(),否则放进HashSet或作为HashMapkey 时行为异常 - IDE 自动生成的
equals()要检查是否包含所有业务关键字段,比如成绩系统里通常以studentId为主键,name可选
用 ArrayList<student></student> 做增删改查,性能卡在哪
单次增删改查平均时间复杂度是 O(n),尤其 get(int) 虽然快(O(1)),但 remove(Object) 或 indexOf() 都要遍历找匹配项。数据量一过几百,界面响应就明显发滞。
- 查学生:如果频繁按
id查,不如额外维护一个Map<string student></string>,get()降到 O(1) - 删学生:避免每次删都
indexOf() + remove(int)两趟遍历,直接用Iterator一次完成 - 批量导入:别用
add()逐个加,先new ArrayList(initialCapacity)预估大小,减少扩容次数
Student 对象属性该用 String 还是包装类,比如 Integer 存成绩
用 Integer 更稳妥。原始类型 int 无法表达“暂无成绩”这种业务语义,而 null 是明确的缺失标识。
立即学习“Java免费学习笔记(深入)”;
- 成绩字段声明为
private Integer score;,初始化为null,而不是0(0 是有效成绩) - 前端或控制台输出时做空判断:
score == null ? "未录入" : score.toString() - 注意
score != null && score > 60这类判断,别漏掉空指针检查;Java 14+ 可用模式匹配简化,但初学者先写全
真正麻烦的不是语法,是把“成绩未录入”和“成绩为 0 分”当成两种不同状态来建模——这个意识比记住 ArrayList 方法更重要。









