Java列表的size()方法性能和技巧

6
我希望了解.size()方法的性能表现。这个方法返回列表中对象数量的引用(比如一个类成员,在向列表添加对象时每次递增)吗?还是会遍历所有对象?哪一个更高效?每次调用.size()
List<Vector3> objects = getCoords();

for (int x = 0; x < objects.size(); x++){
   for (int y = 0; y < objects.size(); y++){
      for (int z = 0; z < objects.size(); z++){
         drawShape(x, y, z);
      }
   }
}

或者通过保存到本地变量:

List<Vector3> objects = getCoords();
int size = objects.size();

for (int x = 0; x < size; x++){
   for (int y = 0; y < size; y++){
      for (int z = 0; z < size; z++){
         drawShape(x, y, z);
      }
   }
}

假设我们的列表中有> 30,000个对象。

哪种方式更快/更有效?

如果我们使用ArrayList<T>List<T> ,这是否重要?

那么对于简单语句:.size().isEmpty()呢?

if (objects != null && objects.size() > 0){
   doThis();
}

或者通过调用.isEmpty()

if (objects != null && !objects.isEmpty()){
   doSomethingElse();
}

类成员,如果记忆无误。您可以查看各种实现的源代码来找出答案,但我真的怀疑迭代方法会被采用。这样做会带来太多性能损失,以至于无法证明节省4个字节的内存是值得的。如果大小不变,则您的两个循环可以等效,并且我认为在这种情况下JITC可以将一个转换为另一个。使用ArrayList<T>还是List<T>取决于灵活性。最终,您选择实际实现。size()isEmpty()解决不同的问题。 - awksp
getCoords() 返回什么类型的 List?也许这并不重要,但值得注意的是,List 只是一个接口,因此它的实现可能会有所不同。 - Fengyang Wang
不需要“挖掘”。查看源代码即可。至于ArrayList vs List:一个是接口。在赋值语句的左侧保留接口具有其优点(更多信息请参见此处的SO)。 - keyser
1个回答

3

Java List 使用一个实例变量来处理大小。当您添加元素时,它会增加大小,而您删除元素时则会减小大小。调用 list.size() 返回一个变量,因此是 O(1)。

List.size() 理论上看起来应该像这样:

public int size() {
    return this.size;
}

调用 List.isEmpty() 是对实例变量 size 是否等于 0 进行布尔检查。

public boolean isEmpty() {
    return (this.size==0);
}

由于这是一个实例变量,所以据我所知,无论您使用什么类型的List,都不重要,因为它们都继承了通用接口并具有所需的add()和其他函数。


这取决于List接口的实现。 - Luiggi Mendoza
1
我认为所有标准的List都会存储大小,但是可能用户自定义的列表不会。 - Fengyang Wang
最好说“实例”变量而不是“类”变量,这样更少歧义。第二个通常指静态成员变量。 - keyser
1
@keyser 很好的发现,我的回答已经被编辑了。 - Mike Elofson
Java的“List”没有使用任何实例变量,因为它是一个接口而不是类。 - David Conrad
1
是的,可以在某个地方加入“实现”这个词 :p - keyser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接