Java跨类克隆ArrayList时抛出IndexOutOfBoundsException异常
异常根因
- 核心问题:
Report类中直接通过new TaskPage()创建了一个全新的TaskPage实例,这个实例从未执行过你写的ArrayList数据填充逻辑,内部所有列表都是刚初始化的空列表(长度为0),此时调用get(0)访问第一个元素直接触发下标越界。你实际填充过数据的TaskPage实例和Report里new的这个空实例完全是两个独立对象,数据不互通。 - 循环边界错误:ArrayList的合法下标范围是
0 ~ 列表长度-1,你写的循环条件k <= tPage.tName.size()会让k最终等于列表长度,哪怕列表有数据,最后一次循环也会触发越界。 - 语法逻辑错误:
- 字符串值比较误用
==:==比较的是两个对象的内存地址,不是内容,判断字符串相等必须用equals()方法。 - 类型不匹配:你定义的
taskDuration是ArrayList<String>类型,但原TaskPage中tDuration是ArrayList<Integer>,克隆强转时会抛出类型转换异常。 - 结果赋值逻辑错误:循环中每次都直接给
res赋新值,之前匹配到的内容会被覆盖,最终只能拿到最后一次循环的结果。 - 无效克隆:你在
init()方法里克隆了列表,但循环遍历的时候还是直接读tPage里的原始公共字段,克隆出来的列表完全没被使用。
- 字符串值比较误用
修复方案
- 第一步:修改Report类的实例持有逻辑,不要在Report内部new空的TaskPage,通过构造方法传入已经填充完数据的TaskPage实例,保证操作的是有真实数据的对象。同时修正
taskDuration的泛型类型和原列表一致。public class Report { TaskPage tPage; public ArrayList<String> taskName; public ArrayList<String> taskDesc; public ArrayList<String> fLName; public ArrayList<String> taskStatus; // 修正类型为Integer,和原列表匹配 public ArrayList<Integer> taskDuration; public ArrayList<String> taskID; public String res = ""; // 构造方法传入已存数据的TaskPage实例 public Report(TaskPage page) { this.tPage = page; } public void init() { taskName = (ArrayList<String>)tPage.tName.clone(); taskDesc = (ArrayList<String>)tPage.tDesc.clone(); fLName = (ArrayList<String>)tPage.fLName.clone(); taskStatus = (ArrayList<String>)tPage.tStatus.clone(); taskDuration = (ArrayList<Integer>)tPage.tDuration.clone(); taskID = (ArrayList<String>)tPage.tID.clone(); } - 第二步:修正
statusDone()方法的循环边界、字符串比较、结果拼接逻辑,同时使用克隆后的列表做遍历,避免原列表后续修改影响报表数据。public void statusDone() { init(); res = ""; // 修正循环条件为k < 列表长度,用克隆后的列表做遍历 for (int k=0; k < taskName.size(); k++) { // 用equals比较字符串内容,常量放前面避免空指针 if ("Done".equals(taskStatus.get(k))) { // 用+=追加结果,不覆盖之前的匹配内容 res += fLName.get(k) + ", " + taskName.get(k) + ", " + taskDuration.get(k) + "\n"; } } // 循环结束后如果没有匹配到任何已完成任务,再返回无数据提示 if (res.isBlank()) { res = "There is nothing to display here!"; } } } - 第三步:修改按钮点击事件的代码,创建Report实例时把当前页面持有真实数据的TaskPage对象传入。如果按钮逻辑就在TaskPage类里,直接传
this即可:private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // 传入持有真实数据的TaskPage实例,不要让Report自己new空对象 Report rpt = new Report(this); rpt.statusDone(); String Status = rpt.res; JOptionPane.showMessageDialog(null, Status); }
内容的提问来源于stack exchange,提问作者SFSA_Despair
相关产品推荐
相关产品推荐

