2015-04-13 3 views
1

я интересно, что компилятор делает за сценой, когда я пишу 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.

ПРИМЕЧАНИЕ: Я прочитал Java документ из for-each цикла (http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html), однако они не упоминается случай, как выше.

Так что я знаю, как работает цикл, но не знаю, что происходит со списком, возвращаемым из инструкции parentObject.getChildObjects().

Моих сомнения:

  1. В первом случае компилятор сохранение списка вернулся из parentObject.getChildObjects() заявления в некоторых переменной температуре, которая скрыта от программиста или звонят оператор каждый раз?

  2. Если он высылает заявление parentObject.getChildObjects(), каждый раз; Как он отслеживает следующие элементы?

+0

Используйте 'javap' для декомпиляции вашего класса, чтобы увидеть разницу. –

+5

Вы прочитали * руководство. * Попробуйте [Спецификация языка Java] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2). Он полностью отвечает на этот вопрос. – EJP

+1

@EJP Или просто [лучшее руководство] (https://blogs.oracle.com/CoreJavaTechTips/entry/using_enhanced_for_loops_with). – biziclop

ответ

0

Что упомянуто выше, что именно происходит за сценой. Просто чтобы добавить к его ответу:

В обоих case 1 & 2 компилятор создаст iterator и сохранит его.

Разница между этими двумя подходами:

Случай 1:

for loop превратится в

for(Iterator<ChildObject> it = parentObject.getChildObjects.iterator; it.hasNext();){ 

} 

ПРИМЕЧАНИЕ:parentObject.getChildObjects, возвращающего List, который реализует Iterable интерфейс , Ни ParentObject, ни ChildObject орудия Iterable.

Это важно знать, как в примере «dit's», его класс реализует интерфейс Iterable.

On Stack: только Iterator сохраняется.

Случай 2:

for loop превратится в

List<ChildObject> myList = parentObject.getChildObjects; 
for(Iterator<ChildObject> it = myList.iterator; it.hasNext();){ 

} 

на стек: iterator сохраняется и myList сохраняется.

Вывод:

Случай 1 лучше, чем 2, если memory usage считается, в противном случае оба подхода совпадают.

1

For-Каждый цикл работает со всеми классами, реализующими Iterable - интерфейс, причиной этого нужно iterator() - операция для преобразования для-каждого синтаксиса в цикле итератора:

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++) 

Для получения дополнительной информации смотрите комментарии к вашему вопросу.

+0

Просто, чтобы быть ясным .. что вы имели в виду, это мой оператор 'parentObject.getChildObjects()' преобразуется в 'Iterator it = parentObject.getChildObjects(). Iterator' ? ... Короче говоря, мы сохраняем итератор, а не весь список ... Поэтому могу ли я сказать, что подход 1 лучше, чем 2, если мы рассматриваем использование памяти? – Ankit

+0

Итератор - это просто обертка для вашего списка. подходы 1 и 2 равны. В обоих случаях компилятор будет вызывать 'list.iterator()'. – dit

+0

Да, это будет вызов 'list.iterator', однако niether I или компилятор сохраняет список в переменной temp в случае 1 .. поэтому делает случай 1 для использования меньше 'stack memory' по сравнению с случаем 2 .. – Ankit

1

Поскольку такие вопросы, как использование памяти были затронуты, я думаю, что стоит отметить, что на практике это вряд ли вы когда-нибудь заметит разницу, так как дополнительные astore и aload инструкции, которые компилятор может поставить в основном будут оптимизированы прочь во время выполнения.

Разница, что имеет значение в том, что с делом 2 вы можете случайно сделать что-то вроде этого:

List<ChildObject> myList = parentObject.getChildObjects; 
for(Iterator<ChildObject> it = myList.iterator; it.hasNext();){ 
    ... 
} 
... 
ChildObject ob = myList.get(0); 

Теперь это не то, что вы должны делать, и именно поэтому случай 1 почти всегда предпочтительнее. Более подробно об этом можно прочитать в разделе 45 (свести к минимуму объем локальных переменных) во втором выпуске «Эффективная Java».

Смежные вопросы