Java作业:如何让TableauPartiel的子列表引用原ArrayList?
解决思路:让TableauPartiel成为原ArrayList的视图而非独立拷贝
你遇到的核心问题是之前的实现都创建了新的ArrayList实例,导致子列表和原列表完全独立。要实现修改子列表影响原列表的效果,我们需要让TableauPartiel本身作为原ArrayList的一个视图——也就是共享同一个底层数组,只是通过偏移量来限制访问的范围。
具体实现方案
我们需要给TableauPartiel添加两个额外的成员变量,用来标记当前视图在原ArrayList中的起始和结束索引,所有操作都基于原列表的引用进行索引转换。
完整代码示例
import java.util.ArrayList; class CoupeDeA { private final int begin; private final int end; public CoupeDeA(int begin, int end) { this.begin = begin; this.end = end; } public int getBegin() { return begin; } public int getEnd() { return end; } } public class TableauPartiel<E> { // 共享的原ArrayList引用 private final ArrayList<E> originalTableau; // 当前视图在原列表中的起始和结束索引(左闭右开规则) private final int viewBegin; private final int viewEnd; // 从数组初始化的构造方法:创建完整视图 public TableauPartiel(E[] arr) { originalTableau = new ArrayList<>(); for (E element : arr) { originalTableau.add(element); } viewBegin = 0; viewEnd = originalTableau.size(); } // 内部构造方法:用于创建子视图,对外隐藏 private TableauPartiel(ArrayList<E> original, int begin, int end) { this.originalTableau = original; this.viewBegin = begin; this.viewEnd = end; } // 获取当前视图的元素数量 public int size() { return viewEnd - viewBegin; } // 获取视图中指定索引的元素 public E get(int index) { if (index < 0 || index >= size()) { throw new IndexOutOfBoundsException("Index out of bounds: " + index); } // 转换为原列表的真实索引 return originalTableau.get(viewBegin + index); } // 修改视图中指定索引的元素 public void set(int index, E element) { if (index < 0 || index >= size()) { throw new IndexOutOfBoundsException("Index out of bounds: " + index); } // 转换为原列表的真实索引并修改 originalTableau.set(viewBegin + index, element); } // 实现coupe方法:返回原列表的子视图 public TableauPartiel<E> coupe(CoupeDeA coupe) throws IndexOutOfBoundsException { int coupeBegin = coupe.getBegin(); int coupeEnd = coupe.getEnd(); // 验证截取范围在当前视图的合法范围内 if (coupeBegin < 0 || coupeEnd > size() || coupeBegin > coupeEnd) { throw new IndexOutOfBoundsException("Invalid coupe range: [" + coupeBegin + ", " + coupeEnd + ")"); } // 计算在原列表中的真实起始和结束索引 int newBegin = viewBegin + coupeBegin; int newEnd = viewBegin + coupeEnd; // 创建并返回新的视图实例,共享原ArrayList return new TableauPartiel<>(originalTableau, newBegin, newEnd); } // 测试用的toString方法,方便查看内容 @Override public String toString() { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < size(); i++) { sb.append(get(i)); if (i != size() - 1) { sb.append(", "); } } sb.append("]"); return sb.toString(); } public static void main(String[] args) { Integer[] arr = {8,7,6,5}; TableauPartiel<Integer> tab = new TableauPartiel<>(arr); System.out.println("原列表tab: " + tab); // 输出 [8, 7, 6, 5] // 截取索引1到3的子视图(左闭右开,对应原列表的7、6) TableauPartiel<Integer> tab2 = tab.coupe(new CoupeDeA(1, 3)); System.out.println("子列表tab2: " + tab2); // 输出 [7, 6] // 修改子列表的索引1位置 tab2.set(1, 45); System.out.println("修改后tab2: " + tab2); // 输出 [7, 45] System.out.println("修改后原列表tab: " + tab); // 输出 [8, 7, 45, 5],符合需求 } }
方案原理说明
- 共享底层数据:所有
TableauPartiel实例(包括原实例和子视图实例)都持有同一个originalTableau引用,没有创建新的ArrayList或拷贝元素。 - 索引转换:每个实例通过
viewBegin和viewEnd限制访问范围,get/set操作会自动将视图索引转换为原列表的真实索引。 - 实时同步修改:修改子视图的元素本质是直接修改原ArrayList的对应位置,因此原实例会立刻看到变化。
对比你之前的实现
你之前的代码要么是创建新数组并拷贝元素(完全独立),要么是用subList(本质也是视图,但被老师禁止)。这个方案手动实现了类似subList的视图逻辑,但完全不依赖JDK的subList方法,完美符合要求。
内容的提问来源于stack exchange,提问作者Tanryoku
相关产品推荐
相关产品推荐

