当我写这样的for loop
1
for(ChildObject child : parentObject.getChildObjects()){
//do something
}
而不是
2
List<ChildObject> myList = parentObject.getChildObjects();
for(ChildObject child : myList){
//do something
}
语句parentObject.getChildObjects()
是一个JPA语句,获取类型是LAZY。
注意:我已阅读for-each
循环(http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html)的java文档,但他们没有提到上述情况。
所以我知道循环是如何工作的,但是不知道从parentObject.getChildObjects()
语句返回的列表发生了什么。
我的疑惑:
第一种情况是编译器将parentObject.getChildObjects()
语句中返回的列表保存在某个临时变量中,这对于程序员是隐藏的,还是每次调用该语句?
如果每次调用语句parentObject.getChildObjects()
;它如何跟踪下一个元素?
答案 0 :(得分:2)
For-Each循环正在使用所有实现Iterable - 接口的类,因为它需要iterator()
- 将for-each语法转换为迭代器循环的操作:
public class ChildObject {
[...]
}
public class ParentObject implements Iterable<ChildObject> {
private List<ChildObject> childObjects;
[...]
@Override
public Iterator<ChildObject> iterator() {
return childObjects.iterator();
}
}
public static void main(String[] args){
ParentObject p = new ParentObject();
[...]
for(ChildObject child : p){
System.out.println(child);
}
}
所以
for(ChildObject child : p)
将转变为:
for(Iterator<ChildObject> it = p.iterator(); it.hasNext();){
ChildObject child = it.next();
[...]
}
这就是为什么你如何对你的前循环进行编码无关紧要。
P.S。如果迭代像int[] array
这样的原始数组,编译器会将您的代码转换为简单的迭代数组循环
for(int i = 0; i < array.length; i++)
有关详情,请查看您问题的评论。
答案 1 :(得分:1)
由于触及内存使用等问题,我认为值得一提的是,在实践中,您不太可能注意到差异,因为编译器可能会有额外的astore
和aload
指令投入将主要在运行时进行优化。
重要的区别在于,对于案例2,您可能会意外地执行以下操作:
List<ChildObject> myList = parentObject.getChildObjects;
for(Iterator<ChildObject> it = myList.iterator; it.hasNext();){
...
}
...
ChildObject ob = myList.get(0);
现在这不是你应该做的事情,这就是为什么案例1几乎总是首选。有关这方面的更多信息,请参阅第二版Effective Java中的第45项(最小化局部变量的范围)。
答案 2 :(得分:0)
dit提到的是幕后发生的事情。只是为了补充他的答案:
在两个case 1 & 2
编译器中都会创建一个iterator
并保存它。
两种方法的区别在于:
案例1:
for loop
将转换为
for(Iterator<ChildObject> it = parentObject.getChildObjects.iterator; it.hasNext();){
}
注意: parentObject.getChildObjects
,返回实现List
接口的Iterable
。 ParentObject
和ChildObject
都不会实现Iterable
。
这很重要,因为在&#34; dit&#34;例如,他的类正在实现Iterable接口。
在堆栈上:仅保存
Iterator
。
案例2:
for loop
将转换为
List<ChildObject> myList = parentObject.getChildObjects;
for(Iterator<ChildObject> it = myList.iterator; it.hasNext();){
}
在堆栈上:保存
iterator
并保存myList
。
<强>结论:强>
如果考虑memory usage
,情况1优于2,否则两种方法都相同。