Java 9下ObservableListWrapper替代方案及编译问题解决咨询
ObservableListWrapper编译错误的方案 这个问题我之前升级Java版本时也踩过坑,Java 9引入的模块系统把很多com.sun开头的内部JavaFX API都封装起来了,com.sun.javafx.collections.ObservableListWrapper就是其中一个,所以才会出现这个访问权限错误。下面给你几个可行的解决办法,按推荐程度排序:
1. 用官方公共API替代(最推荐)
ObservableListWrapper本身就是一个基于普通List实现的ObservableList包装类,JavaFX官方早就提供了标准的替代方法:FXCollections.observableList(List<E>)。
原来的代码比如:
import com.sun.javafx.collections.ObservableListWrapper; // ... ObservableList<String> list = new ObservableListWrapper<>(new ArrayList<>());
直接替换成:
import javafx.collections.FXCollections; import javafx.collections.ObservableList; // ... ObservableList<String> list = FXCollections.observableList(new ArrayList<>());
这个方法返回的ObservableList实现和ObservableListWrapper功能完全一致,而且是JavaFX的公共API,不存在模块访问权限问题,后续版本升级也不会出问题。
2. 自定义包装类(如果需要底层List的直接访问)
如果你需要直接操作包装的底层List(比如ObservableListWrapper的getList()方法),可以自己写一个简单的包装类,或者继承javafx.collections.ModifiableObservableListBase抽象类来实现,示例大概是这样:
import javafx.collections.ModifiableObservableListBase; import java.util.ArrayList; import java.util.List; public class CustomObservableListWrapper<E> extends ModifiableObservableListBase<E> { private final List<E> backingList; public CustomObservableListWrapper(List<E> backingList) { this.backingList = backingList; } @Override public E get(int index) { return backingList.get(index); } @Override public int size() { return backingList.size(); } @Override protected void doAdd(int index, E element) { backingList.add(index, element); } @Override protected E doSet(int index, E element) { return backingList.set(index, element); } @Override protected E doRemove(int index) { return backingList.remove(index); } // 提供获取底层List的方法(如果需要) public List<E> getBackingList() { return backingList; } }
不过这个方法需要自己维护代码,除非你真的需要底层List的直接操作,否则还是优先用第一种方案。
3. 强制导出内部模块(不推荐)
如果暂时不想改代码,可以通过编译和运行时的JVM参数,让javafx.base模块把内部的com.sun.javafx.collections包导出给未命名模块(也就是你的应用所在的classpath环境)。
编译时添加参数:
javac --add-exports javafx.base/com.sun.javafx.collections=ALL-UNNAMED YourClass.java
运行时也要添加同样的参数:
java --add-exports javafx.base/com.sun.javafx.collections=ALL-UNNAMED YourClass
但这个方法不推荐,因为com.sun开头的内部API不属于公共API,Oracle随时可能修改或移除它们,后续升级Java版本大概率会出问题。
内容的提问来源于stack exchange,提问作者Alex T

