2011-03-20 8 views
2

Java의 메모리 점유 및 효율성면에서 완전히 동일합니까?

우선 :Java For Loop의 차이점

Object[] array = new Object[100]; 
int i = 0; 
for (; i < array.length; i++){ 
    Object o = array[i]; 
    //do something 
} 

둘째 :

Object[] array = new Object[100]; 
for (int i = 0; i < array.length; i++){ 
    Object o = array[i]; 
    //do something 
} 

셋째 :

Object[] array = new Object[100]; 
for (Object o : array){ 
    //do something 
} 

답변

6

메모리 사용과 효율성 측면에서 그렇습니다. 그러나 차이점이 있습니다. 첫 번째에서는 i이 루프를 벗어나 존재합니다 (스코프가 있음). 두 번째 때는 그렇지 않습니다. 세 번째 경우에는 인덱스에 액세스하거나 현재 객체의 위치에서 배열 내용을 변경하는 (직접적인) 방법이 없습니다.

+0

대단히 고마워요. 그래서 두 번째 문장에서는 iterator에 대해 하나의 메모리 할당 만있을 것입니다. 또는 각 반복에 대한 다른 할당? 그리고 세 번째로 ... 자바는 숨겨진 반복자를 할당합니까? 그리고 배열 길이에 대한 숨겨진 정수? – Oneiros

+2

맞습니다. 모험이라면 javap을 사용하여 각 종류의 루프에 대해 생성 된 바이트 코드를 볼 수 있습니다. 그들은 거의 동일해야합니다. –

+0

오, 나는 javap에 대해 몰랐다 ... 다시 한번 감사드립니다! :) – Oneiros

1

첫번째 공통 idio 아니다 엠; 나는 그렇게 쓰지 않을 것입니다.

메모리 또는 효율성에 차이가 없습니다. 세 번째는 나중에 JVM에 추가 된 구문 설탕입니다 (JDK 6이라고 생각합니다).

코드가 루프 구조가 아닌 메모리 및 효율성 병목 현상이됩니다.

+2

첫 번째 관용구는 특정 조건에서 루프를 벗어나기를 원하고 나중에 휴식이 있었는지 알아야 할 경우에 매우 유용합니다. 그것을 방아쇠 한 객체의 인덱스 –

0

제 3의 버전은 Java 5와 함께 도입되었으며 generics로 작업을 단순화하도록 설계되었습니다. 루핑되기 전에 배열에 몇 개의 요소가 있는지 판별 할 필요가 없기 때문에 향상됩니다. 현재 위치를 증가시키는 방법을 지정할 필요가 없으므로 카운터 변수 또는 반복기를 만들 필요없이보다 명확한 구현을 제공합니다.

+0

루프의 본문에 현재 색인이 필요하지 않다면 향상된 for-loop 구문이 더 깨끗하다는 데 동의합니다. (한 가지는 인덱스 변수로 몸이 엉망이되는지에 대해 걱정할 필요가 없다는 것입니다.) 제 생각에는 의도하지 않은 autoboxing 오버 헤드를 쉽게 마스킹 할 수 있습니다 (이 특별한 경우는 아니지만). –

0

아니요 정확히 동일하지 않습니다. 그리고 그것은 쉽게 검증 할 수 있습니다.

그냥 다음과 같은 두 가지 기능을 디 컴파일 : 우리가 뭔가가 변수 및 만드는 끝낼 볼 수 있도록

public static void test1(java.lang.Object[]); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: aload_0 
    4: arraylength 
    5: if_icmpge  23 
    8: getstatic  #4; //Field java/lang/System.out:Ljava/io/PrintStream; 
    11: aload_0 
    12: iload_1 
    13: aaload 
    14: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    17: iinc 1, 1 
    20: goto 2 
    23: return 

public void test2(java.lang.Object[]); 
    Code: 
    0: aload_1 
    1: astore_2 
    2: aload_2 
    3: arraylength 
    4: istore_3 
    5: iconst_0 
    6: istore 4 
    8: iload 4 
    10: iload_3 
    11: if_icmpge  34 
    14: aload_2 
    15: iload 4 
    17: aaload 
    18: astore 5 
    20: getstatic  #4; //Field java/lang/System.out:Ljava/io/PrintStream; 
    23: aload 5 
    25: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    28: iinc 4, 1 
    31: goto 8 
    34: return 
} 

난 그냥 println 메소드를 (포함) :

public static void test1(Object[] arr) { 
    for (int i = 0; i < arr.length; i++) { 
     System.out.println(arr[i]); 
    } 
} 

public void test2(Object[] arr) { 
    for(Object o : arr) { 
     System.out.println(o); 
    } 
} 

과 출력에서 ​​볼 javac은 그것을 최적화하지 않는다. 분명히 큰 그림에서 차이점은 중요하지 않으며 측정 할 수는 없지만 여전히 동일한 코드는 아닙니다.)

제 2의 기능에서 정확히 무슨 일이 일어나는지 확실하지 않지만 누군가 원하는 경우 시간을 갖고 코드를 해부하십시오 ;-)

+0

첫 번째 예는 OP의 첫 번째 예를 정확히 추적하지 않습니다. 'System.out.println (arr [i]);'를'Object o = arr [i];로 대체해야합니다. System.out.println (o);'공정한 비교를 수행합니다. 따라서'test2'에서만 각 배열 요소가'o' (지역 변수 # 5)에 저장됩니다. 두 번째 방법은 배열의 길이를 (로컬 변수 # 3에서) 캐싱하고 다른 지역 변수 (# 2)에 'arr'을 복사하는 등 몇 가지 다른 방법을 사용합니다. 이러한 차이는 아마도 컴파일러에서 적용되는 다른 바이트 코드 템플릿 때문일 수 있습니다. –