Что происходит за кулисами, когда я пишу для цикла, как это

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() список, возвращаемый из parentObject.getChildObjects() в некоторой временной переменной, которая скрыта от программиста или вызывает вызов каждый раз?

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

  • 0
    Используйте javap для декомпиляции вашего класса, чтобы увидеть разницу.
  • 5
    Вы прочитали руководство. Попробуйте спецификацию языка Java . Это полностью отвечает на этот вопрос.
Показать ещё 2 комментария
Теги:
for-loop
jpa

3 ответа

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", его класс реализует интерфейс Iterable.

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

Случай 2:

for loop преобразуется в

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

}

On Stack: iterator сохраняется, и myList сохраняется.

Вывод:

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

1

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

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

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

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

1

For-Each Loop работает со всеми классами, реализующими 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();
    [...]
}

Вот почему это не имеет значения, как вы кодируете свой первый цикл.

PS, если вы перебираете примитивный массив, такой как массив int[] array, компилятор преобразует ваш код в простую итерацию по контуру массива

for(int i = 0; i < array.length; i++)

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

  • 0
    Просто чтобы быть понятным ... что вы имели в виду, мой оператор parentObject.getChildObjects() преобразуется в Iterator<childObject> it = parentObject.getChildObjects().iterator ? ... Итак, вкратце, мы сохраняем итератор, а не весь список ... Поэтому я могу сказать, что подход 1 лучше, чем 2, если мы рассмотрим использование памяти?
  • 0
    Итератор - это просто оболочка для вашего списка. подходы 1 и 2 равны. В обоих случаях компилятор вызовет list.iterator() .
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню