Java эффективность анонимных классов - PullRequest
25 голосов
/ 12 июня 2010

Есть ли разница в эффективности (например, время выполнения, размер кода и т. Д.) Между этими двумя способами выполнения действий?

Ниже приведены надуманные примеры, которые создают объекты и ничего не делают, но мои реальные сценарии могут заключаться в создании новых потоков, прослушивателей и т. Д. Предположим, что следующие циклы кода происходят в цикле, чтобы это могло иметь значение.

Использование анонимных объектов:

void doSomething() {
    for (/* Assume some loop */) {
        final Object obj1, obj2; // some free variables

        IWorker anonymousWorker = new IWorker() {
            doWork() {
                // do things that refer to obj1 and obj2
            }
        };
    }
}

Определение класса первым:

void doSomething() {
    for (/* Assume some loop */) {
        Object obj1, obj2;
        IWorker worker = new Worker(obj1, obj2);
    }
}

static class Worker implements IWorker {
    private Object obj1, obj2;
    public CustomObject(Object obj1, Object obj2) {/* blah blah */}

    @Override
    public void doWork() {}
};

Ответы [ 6 ]

39 голосов
/ 12 июня 2010

Практическое отличие * между анонимными классами и классами верхнего уровня заключается в том, что анонимные классы будут содержать неявную ссылку на внешний класс.

Это не проявится в производительности, но повлияет на вас, если вы когда-нибудь сериализуете эти классы.

19 голосов
/ 12 июня 2010

Должна быть небольшая разница в производительности.Если есть разница, она будет на уровне, о котором не стоит беспокоиться.

IMO, вам следует сосредоточиться на написании кода, который читается и обслуживается, и игнорировать «микро» проблемы с производительностью до тех пор, пока у вас не возникнет clear свидетельство того, что они значительны ... основаны на профилировании приложения.

(Для записи, когда анонимный внутренний класс ссылается на final во вложенной области видимости, это реализуетсяна уровне байт-кода с помощью скрытых аргументов конструктора и скрытых атрибутов экземпляра. Байт-коды будут почти такими же, как байт-коды, которые вы получаете от другой вашей реализации.)

18 голосов
/ 12 июня 2010

Важно понимать, что анонимные классы все еще являются классами, которые были известны и полностью скомпилированы во время компиляции. Тот факт, что, например, вы определяете анонимное тело класса, возможно, со многими методами и полями внутри цикла, не означает, что среда выполнения должна компилировать этот тип на каждой итерации. *

Таким образом, любая разница в производительности между двумя подходами незначительна. Важными факторами, которые следует учитывать, являются такие вещи, как читабельность, возможность повторного использования, тестируемость и т. Д.

4 голосов
/ 29 октября 2014

Что касается производительности, вы должны учитывать, должен ли быть создан внутренний класс или нет вообще.

Примером плохой практики является что-то вроде:

public List<String> someMethod() {
       return new ArrayList<String>() {{
                      add("Item one");
                      add("Item two");
              }};
}

Хотя это синтаксическое удобство на первый взгляд выглядит умным, это (часто незамеченное) создает анонимный внутренний класс, объект которого сохраняет ссылку на внешний экземпляр. Поскольку этот объект также передается извне в качестве значения результата someMethod, вы не можете быть уверены, что ваш вызывающий объект делает с этим списком. Если он поместит полученный экземпляр ArrayList в некоторую статическую переменную, ваш текущий объект будет сохранен тоже навсегда!

4 голосов
/ 15 мая 2013

Я действительно заметил существенное снижение производительности при создании экземпляров многих экземпляров анонимного класса.

Думая, что может быть из-за того, что локальный класс статичен, я удалил его, и это не имело никакого значения.1004 * В моем случае я делал что-то 1000, выбрал 3 раза, что составляет 499 500.Версия с локальным классом (независимо от статического или нет) заняла 26 секунд, а версия с анонимным функционально идентичным классом заняла 2 минуты 20 секунд.

0 голосов
/ 12 июня 2010

Рассуждения о производительности кода - отличный способ напрасно тратить время. Ничто не сравнится с фактическим тестированием кода. Если вы беспокоитесь о производительности, измерьте код . Если вы подозреваете, что ваш код не оптимален, профилируйте код , чтобы выяснить, на что тратится время, а затем попытайтесь улучшить эти части. В настоящее время может быть целесообразно изучить байт-код, чтобы понять, может ли это дать вам подсказку, какая реализация более эффективна.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...