每次输入foreach循环时,Java都会创建一个新对象吗? 我不是在谈论每次迭代,但是如果你有一个多次使用的foreach循环,它每次都在创建对象吗?
简单示例:
for(Object o : Objects)
{
for(Object p : Objects2)
{
}
}
每次执行只会有一个p
,或者每个p
会Object o
实例化吗?
垃圾收集器每次退出时都必须从foreach循环中恢复对象吗?
更具体地说,我正在编写一些基于Android的游戏代码。它将以每秒给定的速率迭代所有游戏对象,或者根据具体情况尽可能快地迭代。
可能是过早优化的情况,但如果使用显式for
或while
循环可以保证我不会从循环中获得多余的垃圾收集,那么我可以确定作为项目的编码标准。
更具体地说:
public void update()
{
for(GameObject gObj : gameObjects)
{
gObj.update();
}
}
从一个旨在根据我之前描述的时间进行调用的线程调用update()
。
更新
我在询问是否为p
中的每个o
创建了新的参考Objects
。如果它复制Objects2
中的对象,则不会。那么VM是否必须创建一个新的引用p
,然后它在外部循环的迭代之间收集该引用?更具体地说,在我的情况下,它是否收集方法调用之间的引用?
更新 来自对Matt Ball的回答的评论。 哪个会减少垃圾收集工作?
//Loop just to have it run a number of times
//Could be running the inner foreach numerous time for any reason
for(int i = 0; i < 1000; i++)
{
for(Object o : Objects)
{
o.update();
}
}
VS
Iterator<Object> iter;
//Loop just to have it run a number of times
//Could be running the inner foreach numerous time for any reason
for(int i = 0; i < 1000; i++)
{
iter = Objects.iterator();
while(iter.hasNext());
{
iter.getNext().update();
}
}
更新 比较范围:
import java.util.ArrayList;
import java.util.Iterator;
public class TestLoops
{
public static Iterator<Object> it;
public static ArrayList<Object> objects;
public static void main(String... args)
{
objects = new ArrayList<Object>();
it = objects.iterator();
it = objects.iterator();
//Every time we start a foreach loop, does it creates a new reference?
Iterator<Object> newIt1 = objects.iterator();
Iterator<Object> newIt2 = objects.iterator();
}
}
制作此字节码:
public class TestLoops {
public static java.util.Iterator<java.lang.Object> it;
public static java.util.ArrayList<java.lang.Object> objects;
public TestLoops();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: putstatic #4 // Field objects:Ljava/util/ArrayList;
10: getstatic #4 // Field objects:Ljava/util/ArrayList;
13: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
16: putstatic #6 // Field it:Ljava/util/Iterator;
19: getstatic #4 // Field objects:Ljava/util/ArrayList;
22: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
25: putstatic #6 // Field it:Ljava/util/Iterator;
28: getstatic #4 // Field objects:Ljava/util/ArrayList;
31: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
34: astore_1
35: getstatic #4 // Field objects:Ljava/util/ArrayList;
38: invokevirtual #5 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
41: astore_2
42: return
}
答案 0 :(得分:6)
for-each循环没有神奇的对象构造。语法如下:
for(Object o : Objects)
{
for(Object p : Objects2)
{
}
}
仅简写:
for(Iterator<Object> iter = Objects.iterator(); iter.hasNext();)
{
Object o = iter.next();
for(Iterator<Object> iter2 = Objects2.iterator(); iter2.hasNext();)
{
Object p = iter2.next();
}
}
如果为
iter2
中的每个对象创建了Objects
引用?
这取决于Objects2
的来源。它来自o
吗?它还取决于Objects2.iterator()
的实施方式。期望Iterable#iterator()
返回独立的迭代器,这意味着Objects2.iterator()
几乎肯定会为每次调用返回一个新的Iterator
。但不说明是否在Objects2
(使用iter2
)中迭代对象会创建其他新对象。
总的来说,这听起来像是过早优化。
哪会减少垃圾收集工作?
两者都没有。增强的for循环(又名for-each循环)只是语法糖。编译器生成的字节码是相同的。 Complete example:
package com.stackoverflow;
import java.util.Iterator;
public class Question14640184
{
public void enhancedForLoop(Iterable<Object> objects1, Iterable<Object> objects2)
{
for(Object o1 : objects1)
{
for(Object o2 : objects2)
{
// do something
}
}
}
public void iteratorForLoop(Iterable<Object> objects1, Iterable<Object> objects2)
{
for(Iterator<Object> iter1 = objects1.iterator(); iter1.hasNext();)
{
Object o1 = iter1.next();
for(Iterator<Object> iter2 = objects2.iterator(); iter2.hasNext();)
{
Object o2 = iter2.next();
}
}
}
}
编译:
✗ javac Question14640184.java
✗ javap -c Question14640184
Compiled from "Question14640184.java"
public class com.stackoverflow.Question14640184 extends java.lang.Object{
public com.stackoverflow.Question14640184();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public void enhancedForLoop(java.lang.Iterable, java.lang.Iterable);
Code:
0: aload_1
1: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_3
7: aload_3
8: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 57
16: aload_3
17: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: astore 4
24: aload_2
25: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
30: astore 5
32: aload 5
34: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
39: ifeq 54
42: aload 5
44: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
49: astore 6
51: goto 32
54: goto 7
57: return
public void iteratorForLoop(java.lang.Iterable, java.lang.Iterable);
Code:
0: aload_1
1: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_3
7: aload_3
8: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
13: ifeq 57
16: aload_3
17: invokeinterface #4, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
22: astore 4
24: aload_2
25: invokeinterface #2, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
30: astore 5
32: aload 5
34: invokeinterface #3, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
39:
就像我说的那样, for-each循环仅 syntactic sugar。
这是我刚才所关注的事情。
继续前进,朋友。
答案 1 :(得分:2)
完全取决于Iterable返回的内容。如果它创建了一个新对象,那就这样吧。如果没有,不是。例如,在数组的情况下,元素已经存在,因此不会创建任何对象。同样适用于大多数集合。
几乎可以肯定地创建一个新对象的一种情况是Iterable本身是函数调用的结果,例如:
for (Object o : xyz.getIterable())
但这不是for-each循环的属性,而是函数调用的属性。