例如,这个问答说 List list = new ArrayList()
是可取的,因为它很容易处理更改,您可以更改到其他列表,例如linkedlist。
然而,在下面的例子中,它真的是可取的吗
List<MyClass> data = new ArrayList<>();
//... long code
Random rand = new Random();
for (int i = 0; i < data.size(); i++) {
MyClass record = data.get(rand.nextInt(data.size()));
...//processing
}
此代码包含太多随机访问。如果继任者读到 List<MyClass> data = new ArrayList<>();
并认为“好的,任何列表在这个代码上都没有问题。我添加了一些插入处理,将arraylist更改为linkedlist”。当执行过多的随机访问时,这会导致处理过慢。
不仅是列表,除非实现方法以类似的方式工作,否则按接口声明是可取的,不是吗?
编辑:更改为真正的随机访问
3条答案
按热度按时间j8ag8udp1#
一般原则是,变量的类型应该反映它的用途,而不是对象的“构成”(即其内部实现细节)。
在大多数情况下,重要的是对象可以用作列表,而列表由数组“组成”并不重要,因此标准建议是声明一个类型的变量
List<Foo>
而不是ArrayList<Foo>
.在您的特定情况下,您希望使用对象进行快速随机访问;对象是否由数组“组成”仍然无关紧要,因为任何其他具有快速随机访问的列表实现都可以(例如,的返回值
Arrays.asList
)所以在您的案例中应用一般原则,类型应该反映您希望使用它进行快速随机访问的事实。不幸的是,java没有这样的类型
RandomAccessList<Foo>
. 有一个标记接口RandomAccess
可由实现List
表示它们支持快速随机访问,但声明为RandomAccess fooList = new ArrayList();
因为marker接口没有类似get
.因此,适当的做法是将变量声明为类型
List<Foo>
或者写一条评论说它应该支持快速随机访问(如果列表是本地创建的),或者检查一下fooList instanceof RandomAccess
扔一个IllegalArgumentException
否则(如果列表是从其他地方提供的)。u0sqgete2#
在我看来,这取决于兼容性/抽象是否比性能更重要。如果随机访问是函数性的一个关键特性,那么我认为将输入压缩为arraylist是可以接受的,消费者将不得不将其输入转换为arraylist。
vbkedwbf3#
您的代码示例以完全相同的方式运行,无论您使用:
…或您使用:
在第一个版本中,通过更通用的接口(或超类)引用对象不会改变任何行为。在上面的两个示例中,您都在操作一个以数组为背景的列表
ArrayList
对象。在选择的特定实现时
List
,例如LinkedList
或者ArrayList
,则必须考虑在代码中可能如何使用该列表。我们有多个实现,因为不同的程序有不同的需求。例如,如果您的程序正在按列表中的特定位置执行许多任意访问,请使用ArrayList
. 如果要在列表中插入/删除多个元素,请使用LinkedList
. 每种List
有其独特的优势。通过更通用的接口而不是特定的具体类引用集合的意义在于,当您决定从一种列表更改为另一种列表时,引用该列表的其他代码不会中断。如果您意识到您的代码在列表中间执行插入/删除的次数比按位置执行任意访问的次数要多,您可以更改以下内容:
…对此:
…不破坏任何其他涉及
data
.当然,这假设其他代码由接口上可用的方法满足。如果代码需要调用特定于
ArrayList
类,则必须将该列表作为ArrayList
而不是作为一个List
.你的最后一段不清楚。你提到的“随机访问太多”和“处理太慢”没有得到解释。因此,如果您的问题尚未得到解决,请编辑您的问题。
顺便说一下,请注意
Collections
班级。从中获取随机元素List
,您可以复制列表,然后Collections.shuffle
将元素移动到随机选择的位置。查看此代码在ideone.com上的实时运行。