在Joshua Bloch撰写的Effective Java一书中,讨论了一个班级如何提供“明智选择的受保护方法”作为其内部工作的钩子。
然后,作者引用AbstractList.removeRange()
中的文档:
此方法由此列表上的
clear
操作及其调用 子列表。重写此方法以利用内部的 列表实现可以大大提高性能 此列表及其子列表上的clear
操作。
我的问题是,如何覆盖此方法可以提高性能(而不仅仅是不会覆盖它)?谁能举个例子?
答案 0 :(得分:19)
让我们举一个具体的例子 - 假设您的实现由动态数组支持(例如,这就是ArrayList
的工作原理)。现在,假设您要删除[start,end]范围内的元素。 removeRange
的默认实现方法是使迭代器定位start
,然后调用remove()
适当的次数。
每次调用remove()
时,动态数组实现都必须对位置start + 1
处的所有元素进行混洗,然后向前移回一个点以填充已删除元素中剩余的空白。这可能需要花费时间O(n),因为可能所有的数组元素都需要被拖垮。这意味着如果你要从列表中删除总共k
个元素,那么天真的方法需要花费时间O(kn),因为你正在做O(n)个工作k次。
现在考虑一个更好的方法:将位置end
的元素复制到位置start
,然后将元素end + 1
复制到位置start + 1
等,直到复制所有元素。这要求您只执行O(n)工作,因为每个元素最多移动一次。与朴素算法给出的O(kn)方法相比,这是一个巨大的性能提升。因此,覆盖removeRange
以使用此更高效的算法可以显着提高性能。
希望这有帮助!
答案 1 :(得分:11)
如方法的javadocs中所指定的那样:
此实现获取一个位于fromIndex之前的列表迭代器,并重复调用ListIterator.next,后跟ListIterator.remove,直到删除整个范围。
由于这个抽象类不知道它的子类的内部,它依赖于这个通用算法,该算法将在时间上与被删除的项目数成比例。
例如,如果您实现了一个将元素存储为链接列表的子类。然后,您可以利用此事实并重写此方法,以使用链接列表特定算法(将指针移动到fromIndex
以指向toIndex
),该算法在恒定时间内运行。因此,您可以利用内部优势提高性能。
答案 2 :(得分:0)
只需覆盖此方法,您就可以根据您的要求使用此通用算法作为索引问题。因为它是AbstractList中的受保护方法,也是ArrayList及其实现中的一个,它作为remove()的迭代调用,需要每次将删除元素右侧可用的所有元素移位一个索引。 显然它没有效果,所以你可以让它更好地工作。