В этом случае i
помещается внутри изменяемой ссылки groovy. В Java установка i
будет означать изменение локальной переменной метода, в котором находится этот цикл. Что вызывает кучу технических вопросов о том, что произойдет, если объект функции покинет метод. Но в groovy i
находится в куче.
Это объяснение исходит из байт-кода, насколько я понимаю, который вы можете получить с помощью команды:
javap -c <name of closure class>
Глядя на метод doCall
, сначала ищется объект CallSite
для функтора (поскольку лямбда-выражения могут совместно использовать свои классы, сайты вызовов в основном представляют собой наборы захваченных локальных переменных), и извлекается конкретный i
:
10: getfield #29 // Field i:Lgroovy/lang/Reference;
Как видите, тип i
равен groovy.lang.Reference
. Далее число увеличивается:
27: invokestatic #51 // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.next:(Ljava/lang/Number;)Ljava/lang/Number;
После этого результат загружается обратно в ссылку groovy по адресу:
42: invokevirtual #61 // Method groovy/lang/Reference.set:(Ljava/lang/Object;)V
Это было бы похоже на выполнение чего-то подобного в Java:
for (AtomicInteger i = new AtomicInteger(); i.get() < n;) {
((Runnable) () -> System.out.println(i.getAndIncrement())).run();
}
Где я использовал AtomicInteger
для представления изменяемого int
, который находится в куче, а не в слоте локальной переменной.
person
Jorn Vernee
schedule
18.03.2017