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

如何在Java中使用观察者模式监听ArrayList的变更?

解决ArrayList变更监听的问题

嘿,这个场景我太熟悉了!你当前的实现只有在替换整个列表(调用setValues)时才会触发通知,但如果外部拿到getValues()返回的ArrayList引用后,直接调用add()、remove()、set()这类方法,你的MyList完全感知不到——因为这些操作绕开了你的类,直接修改了底层列表。下面给你几个实用的解决方案:

方案一:自定义可观察的ArrayList子类

最直接的方式是自己写一个继承ArrayList的子类,重写所有会修改列表内容的方法,在这些方法里触发变更通知。这样不管是通过你的MyList类还是直接操作列表,只要修改了内容都会触发通知。

代码实现

首先创建自定义的可观察列表:

import java.util.ArrayList;
import java.util.Map;

public class ObservableArrayList extends ArrayList<Map<String, Object>> {
    private MyList parent;

    public ObservableArrayList(MyList parent) {
        this.parent = parent;
    }

    @Override
    public boolean add(Map<String, Object> e) {
        boolean result = super.add(e);
        parent.notifyChange();
        return result;
    }

    @Override
    public void add(int index, Map<String, Object> element) {
        super.add(index, element);
        parent.notifyChange();
    }

    @Override
    public boolean addAll(java.util.Collection<? extends Map<String, Object>> c) {
        boolean result = super.addAll(c);
        if (result) {
            parent.notifyChange();
        }
        return result;
    }

    @Override
    public boolean addAll(int index, java.util.Collection<? extends Map<String, Object>> c) {
        boolean result = super.addAll(index, c);
        if (result) {
            parent.notifyChange();
        }
        return result;
    }

    @Override
    public Map<String, Object> remove(int index) {
        Map<String, Object> result = super.remove(index);
        parent.notifyChange();
        return result;
    }

    @Override
    public boolean remove(Object o) {
        boolean result = super.remove(o);
        if (result) {
            parent.notifyChange();
        }
        return result;
    }

    @Override
    public Map<String, Object> set(int index, Map<String, Object> element) {
        Map<String, Object> result = super.set(index, element);
        parent.notifyChange();
        return result;
    }

    @Override
    public void clear() {
        super.clear();
        parent.notifyChange();
    }
}

然后修改你的MyList类,使用这个自定义列表,并添加统一的通知方法:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;

public class MyList extends Observable {
    private List<Map<String, Object>> values;

    public MyList() {
        // 初始化时就用自定义的可观察列表
        this.values = new ObservableArrayList(this);
    }

    public List<Map<String, Object>> getValues() {
        // 可选:返回不可变视图,强制外部通过你的类修改列表
        // return Collections.unmodifiableList(values);
        return values;
    }

    public void setValues(List<Map<String, Object>> values) {
        if (!this.values.equals(values)) {
            this.values.clear();
            this.values.addAll(values);
            notifyChange();
        }
    }

    // 统一的通知方法,避免重复代码
    public void notifyChange() {
        setChanged();
        notifyObservers();
    }

    public static void main(String[] args) {
        MyList myList = new MyList();
        Notify notify = new Notify();
        myList.addObserver(notify);

        // 现在直接操作列表也会触发通知
        Map<String, Object> map = new HashMap<>();
        map.put("string_value", "test");
        myList.getValues().add(map); // 会打印"List has been changed"
    }
}

方案二:使用JavaFX的ObservableList(如果允许引入JavaFX)

JavaFX自带了ObservableList,它原生支持监听列表的所有变更(添加、删除、修改),不需要自己写大量的重写代码。你可以直接用它来替换普通的ArrayList,然后注册监听器触发你的Observable通知。

代码实现

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import java.util.Map;
import java.util.Observable;

public class MyList extends Observable {
    private ObservableList<Map<String, Object>> values;

    public MyList() {
        values = FXCollections.observableArrayList();
        // 给ObservableList添加变更监听器
        values.addListener((ListChangeListener.Change<? extends Map<String, Object>> change) -> {
            notifyChange();
        });
    }

    public ObservableList<Map<String, Object>> getValues() {
        return values;
    }

    public void setValues(List<Map<String, Object>> values) {
        this.values.setAll(values);
    }

    public void notifyChange() {
        setChanged();
        notifyObservers();
    }

    // 测试代码同之前,这里省略...
}

注意:这个方案需要引入JavaFX的依赖,如果是普通的Java SE项目,可能需要手动添加依赖。

方案三:使用Guava的ForwardingList(如果允许引入Guava库)

Google Guava的ForwardingList可以帮你轻松装饰一个列表,只需要重写你关心的修改方法,不用手动重写所有方法,代码会更简洁。

代码实现

首先引入Guava依赖,然后编写装饰类:

import com.google.common.collect.ForwardingList;
import java.util.List;
import java.util.Map;

public class ForwardingObservableList extends ForwardingList<Map<String, Object>> {
    private final List<Map<String, Object>> delegate;
    private final MyList parent;

    public ForwardingObservableList(List<Map<String, Object>> delegate, MyList parent) {
        this.delegate = delegate;
        this.parent = parent;
    }

    @Override
    protected List<Map<String, Object>> delegate() {
        return delegate;
    }

    @Override
    public boolean add(Map<String, Object> element) {
        boolean result = super.add(element);
        parent.notifyChange();
        return result;
    }

    @Override
    public Map<String, Object> set(int index, Map<String, Object> element) {
        Map<String, Object> result = super.set(index, element);
        parent.notifyChange();
        return result;
    }

    @Override
    public void clear() {
        super.clear();
        parent.notifyChange();
    }

    // 其他修改方法如remove、addAll等,按需重写即可
}

然后修改MyList类:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Observable;

public class MyList extends Observable {
    private List<Map<String, Object>> values;

    public MyList() {
        this.values = new ForwardingObservableList(new ArrayList<>(), this);
    }

    // 其余方法同方案一,这里省略...
}

关键提醒

不管用哪种方案,都要注意不要暴露底层列表的可修改引用——如果外部可以直接拿到原始列表并修改,你的监听逻辑就可能失效。最好的做法是:

  • 把所有修改列表的操作都封装在MyList类中
  • 或者在getValues()中返回Collections.unmodifiableList(values),强制外部只能通过你的类提供的方法修改列表

内容的提问来源于stack exchange,提问作者Akshay Bande

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:39:26