如何在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
相关产品推荐
相关产品推荐

