我想知道,您可以在现有的size()
缓存上调用ArrayList<T>
方法吗?
或者,在性能关键代码中,我只将size()
存储在本地int中是否更可取?
如果您在调用size()
之间不添加/删除项目,我希望它确实可以缓存。
我是对的吗?
更新
我不是在谈论内联或类似的事情。我只是想知道方法size()
本身是在内部缓存值,还是每次调用它时都会动态计算。
答案 0 :(得分:12)
我认为我不会说它是“缓存”的 - 但它只是存储在一个字段中,所以它足够快以便经常调用。
size()
的Sun JDK实现只是:
public int size() {
return size;
}
答案 1 :(得分:4)
是
快速浏览Java源代码会告诉您答案。
答案 2 :(得分:2)
我肯定不知道答案,但我的猜测是:不。 Java编译器(缺少特殊的套件ArrayList)无法知道您调用的函数将是非变异的,因此,size()的调用应该返回相同的值。因此,我发现Java编译器很可能不会重复调用size()并将它们存储在临时值中。如果您需要这种级别的优化,那么您应该自己将值存储在本地变量中。否则,是的,您将支付与调用size()方法相关的函数调用开销。但请注意,对于ArrayList,size()方法是O(1)(尽管函数调用开销非常大)。就个人而言,我会从循环中分解出对size()的任何调用,并在适用的地方手动存储它们。
修改的
尽管Java编译器无法执行这样的优化,但已经恰当地指出JIT可以内联ArrayList.size()的实现,这样它只需要与字段访问相同,而无需任何额外的方法调用开销,所以实际上成本可以忽略不计,尽管你可能仍然可以通过手动保存一个临时值来节省一些(这可能会消除内存查找,而是从CPU寄存器中提供变量)。
答案 3 :(得分:2)
这是OpenJDK version中的实施:
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
所以它和方法调用一样好。 HotSpot很可能不会缓存此方法返回的值,因此如果您确实 THAT ,则可以自行缓存它。除非你的分析表明这是一个瓶颈,但是(不太可能),你应该只关注自己的可读性,而不是一个简单的方法调用是否缓存了一个字段的值。
答案 4 :(得分:0)
ArrayList的明显实现是将字段内部存储在字段中。如果必须计算,即使在调整大小后,我会感到非常惊讶。
答案 5 :(得分:0)
为什么需要?毕竟,ArrayList实现了一个由数组支持的List接口。
我认为它只有一个size
成员,当你插入东西时递增,当你删除时递减,然后它只返回它。
我现在还没有看过比API文档更多的内容。
答案 6 :(得分:0)
如果缓存size()
方法的结果会显着提高性能(有时会这样做 - 我会经常看到ArrayList.size()
作为我-Xprof
输出中的顶级编译方法)然后考虑转换整个列表到一个数组,以获得更大的加速。
如果您定期迭代列表但很少更新它,这里有一个可行的技巧:
class FooProcessor {
private Foo[] fooArray = null;
private List<Foo> fooList = new ArrayList<Foo>();
public void addFoo(Foo foo) {
fooList.add(foo);
fooArray = null;
}
public void processAllFoos() {
Foo[] foos = getFooArray();
for (int i = 0; i < foos.length; ++ i) {
process(foos[i]);
}
}
private void getFooArray() {
if (fooArray == null) {
Foo[] tmpArray = new Foo[fooList.size()];
fooArray = fooList.toArray(tmpArray);
}
return fooArray;
}
}