如果你发现在一个接口使用有如下定义方法: [backcolor=white !important][size=1em] | [size=1em][size=1em]public String[] getParameters();
|
那么你应该认真反思。数组不仅仅老式,而且我们有合理的理由避免暴露它们。在这篇文章中,我将试图总结在Java API中使用数组的缺陷。首先从最出人意料的一个例子开始。 数组导致性能不佳 你可能认为使用数组是最快速的,因为数组是大多数collection实现的底层数据结构。使用一个纯数组怎么会比使用一个包含数组的对象性能更低? 让我们先从这个看起来很熟悉的普遍的习惯用法开始: [backcolor=white !important][size=1em][size=1em]1
[size=1em]2
[size=1em]3
| [size=1em][size=1em]public String[] getNames() {
[size=1em] return namesList.toArray( new String[ namesList.size() ] );
[size=1em]}
|
这个方法从一个用来在其内部保存数据的可变集合处创建了一个数据. 它通过提供一个确切大小的数组来尝试优化数组的创建. 有趣的是,这一“优化”使得其比下面的更简单的版本速度还要慢(请看图表中绿色VS橘色条): [backcolor=white !important][size=1em][size=1em]1
[size=1em]2
[size=1em]3
| [size=1em][size=1em]public String[] getNames() {
[size=1em] return namesList.toArray( new String[ 0 ] );
[size=1em]}
|
不过,如果方法返回的是一个List, 创建防御式的副本又更加的快了 (红条): [backcolor=white !important][size=1em][size=1em]1
[size=1em]2
[size=1em]3
| [size=1em][size=1em]public List<String> getNames() {
[size=1em] return new ArrayList( namesList );
[size=1em]}
|
不同之处在于一个ArrayList将它的数据项放在一个Object[]数组中,并且使用的是无类型的toArray方法,其比有类型的方法要快很多(蓝条). 这是类型安全的,因为无类型的数组时封装在由编译器检查的泛型类型ArrayList<T>中的. 这个图标展示了一个在Java 7上n=5的参考标准. 不过,更多的数据项或者是另外一个VM情况系啊,这幅图片并不会改变太多. CPU的开销可能并不会太剧烈,但是会有增长. 机会有一个数组的使用者应该将其转换到一个集合中去,以便利用它做任何事情, 然后将结果转换回一个数组,来送进另外一个接口的方法中,诸如此类做法. 使用一个简单的数组列表,而不是可以提高性能的一个数组,无需过多的奔波。数组列表对包装数组增加了一个持续的32字节开销。例如,十个对象的一个数组,需要104个字节,一个数组列表有136字节。使用集合,你甚至可以决定返回内部列表一个不可修改的版本: [backcolor=white !important][size=1em][size=1em]1
[size=1em]2
[size=1em]3
| [size=1em][size=1em]public list<string>getnames()
[size=1em] return collections.unmodifiablelist(namelist);
[size=1em]}
|
在常数时间内完成这个操作,因此它比任何上述(黄色条)要快很多。这与备用副本不一样。当你的内部数据库变更时,可以改变一个不可修改的集合。如果发生这种情况,客户可以运行ConcurrentModificationException.当迭代此项目时,它可能被认为是一个在运行时,接口提供了一个抛出Unsupportoperationexception的方法的不友好界面。不过,至少会在内部使用,这个方法对于一个备用副本来说,可能是一个高性能的解决方案-使用数组,这是不可能的 |