让我们举一个例子来简化它。我构建了一个构造函数采用integer
和List<Integer>
的列表。我的列表将包含给定列表的所有元素乘以integer
。我的列表不存储新元素,而是动态计算它们:
class MyList extends AbstractList<Integer> implements RandomAccess {
private final int multiplier;
private final List<Integer> list;
public MyList(int multiplier, List<Integer> list) {
this.multiplier = multiplier;
this.list = list;
}
@Override
public Integer get(int index) {
return list.get(index) * multiplier;
}
@Override
public int size() {
return list.size();
}
}
然后,我们可以使用new MyList(3, list)
致电list = [0, 1, 2, 3]
以获取[0, 3, 6, 9]
。
我想限制开发人员给MyList
构造函数一个也是RandomAccess
的列表,以确保他不会破坏性能。
我尝试用以下内容更改构造函数:
public <E extends List<Integer> & RandomAccess> MyList(int multiplier, E list)
MyList
不是问题,但现在我们无法在不使用List<Integer>
和RandomAccess
ArrayList<Integer>
的实现的情况下调用构造函数。因此,拥有此列表的人:List<Integer> list = new ArrayList<>();
无法new MyList(3, list);
(因为它是使用List<Integer>
而不是ArrayList<Integer>
声明的。)
我的另一个解决方案就是这个:
public MyList(int multiplier, List<Integer> list) {
if(!(list instanceof RandomAccess)) {
// Do something like log or throw exception
}
this.multiplier = multiplier;
this.list = list;
}
但是现在我无法在编译时检查列表是否实现了RandomAccess
,我需要使用instanceof
并且我讨厌这样做。
我很确定有更好的方法,但它是什么?
答案 0 :(得分:1)
您可以采用Collections.unmodifiableList
使用的解决方案。而不是公共构造函数,有一个静态方法返回两个实现之一,一个实现RandomAccess
,另一个不实现。
以下是Collections.unmodifiableList
的代码。
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
我知道你说你不喜欢使用instanceof
。我也不是,但有时这是最好的事情。
请注意使用构造函数的解决方案
public <E extends List<Integer> & RandomAccess> MyList(int multiplier, E list)
不仅仅是丑陋的,因为它迫使程序员施放(例如到ArrayList
),但它实际上并不起作用。例如,如果list
是Collections$UnmodifiableRandomAccessList
的实例,则甚至无法将其强制转换为同时实现List
和RandomAccess
的类型,因为Collections$UnmodifiableRandomAccessList
是私人的。
答案 1 :(得分:1)
我建议使用instanceof
。事实上,这正是RandomAccess
文档建议的内容:
鼓励通用列表算法检查给定列表 是应用算法之前的此接口的实例 如果将其应用于顺序,则会提供较差的性能 访问列表,并在必要时改变其行为以保证 可接受的表现。
您的构造函数可能有两个实现。如果RandomAccess
已实施,则会存储对List
的引用,否则会创建新的ArrayList
并将所有元素复制到其中:
class MyList {
private final int multiplier;
private final List<Integer> list;
public MyList(int multiplier, List<Integer> list) {
this.multiplier = multiplier;
if (list instanceof RandomAccess)
this.list = list;
else
this.list = new ArrayList<>(list);
}
public int get(int index) {
return multiplier * list.get(index);
}
}
答案 2 :(得分:0)
如果你的类需要一个随机访问列表,那么你的类应该处理它而不是将你的类的需求推送到调用者。此外,在构造函数中进行乘法会更简单 - 您必须在某个时刻执行此操作,但提前执行意味着您可以丢弃大量代码:
class MyList extends ArrayList<Integer> {
public MyList(int multiplier, List<Integer> list) {
for (Integer i : list)
add(i * multiplier);
}
}
这就是你所需要的,和它更安全:通过你的推荐,你的列表和调用者都有对列表的引用。如果在调用构造函数后调用更改了列表,则使用相乘列表的其他代码将意外地看到列表中的值发生更改。