You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中ArrayList移除自定义Coin派生类对象的编译报错问题咨询

编译报错与功能失效的根因

当前代码存在两层逻辑问题,从编译阶段到运行时的问题依次是:

  1. 直接触发编译报错的原因
    你在移除方法里写的coins.remove(Nickel())、coins.remove(Dime())写法,没有加new关键字。编译器会把不带new的类名加括号的形式,识别为调用当前类定义的同名无参方法,但PiggyBank类里根本不存在名为Nickel()、Dime()的实例方法,自然会抛出“方法未定义”的编译错误。
  2. 就算补上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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 06:45:04