Java中ArrayList移除自定义Coin派生类对象的编译报错问题咨询
编译报错与功能失效的根因
当前代码存在两层逻辑问题,从编译阶段到运行时的问题依次是:
- 直接触发编译报错的原因
你在移除方法里写的coins.remove(Nickel())、coins.remove(Dime())写法,没有加new关键字。编译器会把不带new的类名加括号的形式,识别为调用当前类定义的同名无参方法,但PiggyBank类里根本不存在名为Nickel()、Dime()的实例方法,自然会抛出“方法未定义”的编译错误。 - 就算补上new关键字也无法实现需求
哪怕你把代码改成coins.remove(new Nickel()),也删不掉集合里已有的硬币对象。因为ArrayList的remove(Object o)方法,是靠元素的equals()方法匹配目标对象的;你的自定义Coin派生类没有重写equals逻辑,默认沿用Object类的“内存地址比对”规则——只有和集合里存储的对象是同一个内存地址的实例,才能被匹配删除,你临时new出来的新对象和集合里已有对象的地址完全不同,根本无法命中删除逻辑。
可直接落地的修正实现
要达成“从集合中移除指定类型硬币”的需求,不需要依赖新对象的equals匹配,只需要遍历集合,按元素的实际类型做判断,找到匹配项后通过迭代器安全移除即可,修正的核心逻辑包括:
- 用ArrayList自带的迭代器遍历元素,通过
instanceof判断每个元素的类型,匹配到目标类型后直接调用迭代器的remove()方法删除,避免普通for循环移除时的索引偏移、并发修改异常问题 - 匹配到第一个目标类型元素后就终止遍历,和原方法的“移除单个对应硬币”的逻辑保持一致
修正后的完整可运行代码:
package more_java; import java.util.ArrayList; import java.util.Iterator; public class PiggyBank { private static ArrayList<Coin> coins = new ArrayList<Coin>(); public PiggyBank(ArrayList<Coin> coins) { PiggyBank.coins = coins; } public static void addNickel(){coins.add(new Nickel());} public static void addDime(){coins.add(new Dime());} public static void addQuarter(){coins.add(new Quarter());} public static void addLoonie(){coins.add(new Loonie());} public static void addToonie(){coins.add(new Toonie());} public static void removeNickel() { Iterator<Coin> coinIterator = coins.iterator(); while (coinIterator.hasNext()) { Coin currentCoin = coinIterator.next(); // 判断当前元素是否为Nickel类型 if (currentCoin instanceof Nickel) { coinIterator.remove(); break; } } } public static void removeDime() { Iterator<Coin> coinIterator = coins.iterator(); while (coinIterator.hasNext()) { Coin currentCoin = coinIterator.next(); if (currentCoin instanceof Dime) { coinIterator.remove(); break; } } } // 按照完全相同的逻辑,即可补全Quarter、Loonie、Toonie的移除方法 }
常见踩坑提醒
- 不要使用普通for循环从前往后遍历删除元素:删除位置i的元素后,后续元素会整体向前移位,如果不手动将索引i减1,会跳过相邻位置元素的判断,甚至触发数组下标越界异常。
- 如果业务需要移除集合中所有对应类型的硬币,只要去掉上述代码里的
break语句即可。 - 你的场景里所有同类型硬币面额完全一致,也可以选择给所有Coin派生类重写
equals()和hashCode()方法,规则为“同面额硬币判定为相等”,这种情况下就可以直接用coins.remove(new Nickel())的简写方式实现删除,但这种写法需要改动现有Coin类的逻辑,相比之下遍历判断类型的方式不需要改动原有类代码,兼容性更好。
内容的提问来源于stack exchange,提问作者FTeng
相关产品推荐
相关产品推荐

