Разницы почти нет. На самом деле существует старая поговорка о замыканиях и объектах. Закрытия - это объект бедняка, а объекты - это закрытие бедняка. Оба одинаково сильны с точки зрения того, что они могут сделать. Мы спорим только из-за выразительности.
В Java мы моделируем замыкания с помощью анонимных объектов. На самом деле небольшая история здесь заключается в том, что изначально Java имела возможность изменять внешнюю область без использования final. Это работает и прекрасно работает для объектов, размещенных в локальной области метода, но когда дело доходит до примитивов, это вызывает много противоречий. Примитивы размещаются в стеке, поэтому для того, чтобы они жили после выполнения внешнего метода, Java должна была бы выделить память в куче и переместить эти элементы в кучу. В то время люди были совсем новичками в сборке мусора и не доверяли ей, так что утверждение было то, что Java не должна выделять память без явного указания программиста. В попытке достичь компромисса Java решила использовать ключевое слово final.
http://madbean.com/2003/mb2003-49/
Теперь интересно то, что Java могла бы снять это ограничение и использовать окончательное ключевое слово по желанию теперь, когда всем более удобно работать со сборщиком мусора, и оно может быть полностью совместимо с языковой точки зрения. Хотя обойти эту проблему просто, можно определить переменные экземпляра в вашем анонимном объекте, и вы можете изменять их по своему усмотрению. Фактически это мог бы быть простой способ реализовать ссылки стиля закрытия на локальную область путем добавления открытых переменных экземпляра к анонимному классу через компилятор и переписывания исходного кода, чтобы использовать их вместо переменных стека.
public Object someFunction() {
int someValue = 0;
SomeAnonymousClass implementation = new SomeAnonymousClass() {
public boolean callback() {
someValue++;
}
}
implementation.callback();
return someValue;
}
Будет переписано в:
public Object someFunction() {
SomeAnonymousClass implementation = new SomeAnonymousClass() {
public int someValue = 0;
public boolean callback() {
someValue++;
}
}
implementation.callback();
// all references to someValue could be rewritten to
// use this instance variable instead.
return implementation.someValue;
}
Я думаю, что причина, по которой люди жалуются на анонимные внутренние классы, больше связана со статической типизацией, чем с динамической типизацией. В Java мы должны определить согласованный интерфейс для разработчика анонимного класса и кода, принимающего анонимный класс. Мы должны сделать это, чтобы мы могли проверять все во время компиляции. Если бы у нас были функции первого класса, тогда Java должен был бы определить синтаксис для объявления параметров метода и возвращаемых типов как типа данных, чтобы оставаться статически типизированным языком для безопасности типов. Это было бы почти так же сложно, как определить интерфейс. (Интерфейс может определять несколько методов, синтаксис для объявления методов 1-го класса будет только для одного метода). Вы можете думать об этом как о синтаксисе интерфейса короткой формы. Под капотом компилятор может преобразовать краткую запись формы в интерфейс во время компиляции.
Есть много вещей, которые можно было бы сделать с Java, чтобы улучшить работу с Anonymous Class, не отказываясь от языка или серьезных операций.