Оптимизация метода equals () - PullRequest
5 голосов
/ 22 июля 2009

Метод equals() (и в этом отношении также метод compareTo()) может стать горячей точкой производительности (например, при высокой посещаемости HashMap). Мне было интересно, какие приемы люди приняли, чтобы оптимизировать эти методы для этих случаев, когда они оказываются необходимыми.

IntelliJ IDEA, например, генерирует следующее:

public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ...
}

Что еще вам встречалось, что может служить руководством для написания метода equals() с хорошими показателями?

Ответы [ 7 ]

14 голосов
/ 22 июля 2009

Некоторые общие идеи, которые не обязательно специфичны для equals()

  • Ошибка как можно раньше . Как и во фрагменте, который вы разместили, сначала начните с самых широких критериев исключения, а затем сделайте его более мелкозернистым, чтобы метод мог вернуться как можно скорее
  • Сравнить только атрибуты, необходимые для равенства . Я иногда видел, как люди сравнивают каждый отдельный фрагмент информации, предоставляемой классом, хотя на самом деле только несколько атрибутов играют семантическую роль в равенстве двух экземпляров класса. Это, конечно, сильно зависит от вашего класса и дизайна
  • Избегайте рекурсии по равенству, если это возможно . В зависимости от того, какие атрибуты класса вы сравниваете, вы можете попасть в ситуации, когда вы рекурсивно вызываете equals() для себя или других объектов, что может иметь скрытое влияние на производительность

В дополнение к соображениям производительности не забывайте о equals контракте API , чтобы обеспечить равенство рефлексивных , симметричных , транзитивный и непротиворечивый и всегда отменять hashcode() также, когда вы переопределяете equals().

5 голосов
/ 22 июля 2009

Как написать метод равенства в Java - чрезвычайно подробная и хорошо написанная статья, объясняющая типичные ошибки при написании метода равенства и способы их избежать.

4 голосов
/ 22 июля 2009

Я думаю, что вы уже в ключевой части этого, потому что вы сказали:

... когда они окажутся необходимыми.

Запомните общие правила оптимизации:

  1. Не
  2. Не ... пока
  3. Профиль перед оптимизацией

Я слышал их в классе лет назад, и насколько я могу судить, C2 является источником.

2 голосов
/ 22 июля 2009

Ознакомьтесь с книгой Джошуа Блоха "Эффективная Ява". Там есть несколько удивительных советов и целый раздел по этому вопросу. Гудлак!

1 голос
/ 22 июля 2009

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

Вы можете быть в состоянии подтвердить, что определенные сценарии никогда не выполняются, поэтому их не нужно кодировать в пределах equals(), например:

  • сравнение null
  • сравнение разных типов
  • сравнивая себя

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

1 голос
/ 22 июля 2009

Вы можете взять реплику из string interning .

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

0 голосов
/ 22 июля 2009

Я предлагаю сделать HashMap больше, это равно () дорого (например, путем уменьшения коэффициента загрузки). Таким образом, у вас будет меньше коллизий, и, надеюсь, если (o == this) вернет true, то совпадет чаще всего.

...