В Java есть ли разница в производительности между ссылкой на поле через getter и через переменную?

StackOverflow https://stackoverflow.com/questions/1195849

Вопрос

Есть ли какие-то различия между выполнением

Field field = something.getSomethingElse().getField();
if (field == 0) {
//do something    
}
somelist.add(field);

против

if (something.getSomethingElse().getField() == 0) {
//do something    
}
somelist.add(something.getSomethingElse().getField());

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

Обратите внимание, что это скорее академический вопрос (школа просто любопытных), чем практический.

Это было полезно?

Решение

При условии, что getSomethingElse() определяется как

public SomethingElse getSomethingElse() {
    return this.somethingElse;
}

разница в производительности будет минимальной (или нулевой, если она будет встроена).Однако в реальной жизни вы не всегда можете быть уверены в этом — за кулисами может происходить некоторая обработка (не обязательно в самом объекте, а, скажем, через прокси-сервер AOP).Поэтому сохранение результата в переменной для повторного доступа может быть хорошей идеей.

Другие советы

Это незначительный вред.Не беспокойтесь об этом слишком сильно, иначе вы станете жертвой преждевременной оптимизации.Если ваше приложение работает медленно, это не причина.

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

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

Существует снижение производительности (которое может быть настолько небольшим, что его можно пренебречь). Тем не менее, JVM может встроить это и все вызовы для повышения производительности.

Будет лучше, если вы оставите второй путь.

Нет, если у вас хорошая JVM, например HotSpot от Sun.Он будет встроен и скомпилирует (в машинный код) геттеры.

Использование геттеров, как правило, является очень хорошей практикой в качестве защитной меры и общего сокрытия информации.

Один момент, на который следует обратить внимание при использовании Java для написания приложений для Android, находится здесь:http://developer.android.com/training/articles/perf-tips.html#GettersSetters

В родных языках, таких как C ++, обычной практикой является использование методов получения (i = getCount()) вместо прямого доступа к полю (i = mCount).Это это отличная привычка для C++, и это часто практикуется в других объекта ориентированных языков, как C# и Java, потому что компилятор обычно встроенный доступа, и если вам необходимо ограничить или отладки поле Открыть вы можете добавить код в любое время.

Однако это плохая идея для Android. Вызовы виртуальных методов дороги, намного дороже, чем поиск по полю экземпляра.Разумно следовать распространенным методам объектно-ориентированного программирования и иметь средства получения и установки в общедоступном интерфейсе, но внутри класса вы всегда должны обращаться к полям напрямую.

Без JIT-компилятором, прямой доступ к полю примерно в 3 раза быстрее, чем вызов тривиальные геттеры.С помощью JIT (где прямой доступ к полю такой же дешевый, как доступ к локальному), прямой доступ к полю примерно в 7 раз быстрее, чем вызов тривиального средства получения.

Обратите внимание, что если вы используете ProGuard, у вас может быть лучшее из обоих миров, потому что ProGuard может встроить средства доступа для вас.

Если метод представляет собой простой метод получения без какой-либо обработки, это не проблема.Если это требует обширных расчетов, недвижимость в любом случае не будет соответствовать вашим требованиям.

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

Я бы не беспокоился о разнице в производительности.Лучше не думать об этом и вместо этого потратить время на профилирование вашего кода в реалистичном сценарии.Скорее всего, вы обнаружите, что медленные части вашей программы находятся не там, где вы думаете.

В этом посте говорится о виртуальной машине CLI, а не о JVM, но каждая из них может делать схожие вещи, поэтому я считаю, что это актуально.

Я решаю эту конкретную проблему особым образом для своего JIT.Обратите внимание, что приведенное здесь описание является концептуальным, и код реализует его несколько другим способом из соображений производительности.Когда я загружаю сборку, я делаю пометку в дескрипторе метода, если она просто возвращает поле-член.Позже, когда я буду выполнять JIT-компиляцию других методов, я заменяю все call инструкции к этим методам в байт-коде с ldfld инструкцию перед передачей ее генератору собственного кода.Таким образом я могу:

  1. Экономьте время в JIT (ldfld JIT требует меньше процессорного времени, чем call).
  2. Встроенные свойства даже в базовый компилятор.
  3. В целом гарантируется, что использование шаблона общедоступных свойств/частных полей не приведет к каким-либо потерям производительности при отключении отладчика.(Когда подключен отладчик, я не могу встроить средства доступа.)

Я не сомневаюсь, что известные компании в области технологий виртуальных машин уже реализуют нечто подобное (и, возможно, даже лучше) в своих продуктах.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top