Java: используйте toString(). Equals () против equals()

Это вопрос теории. У меня есть объект моего собственного дизайна с кучей переменных, методов и т. Д. Я переопределил метод toString, главным образом для целей ведения журнала, чтобы вернуть значение переменных. Мне кажется, что самый простой и простой способ сравнить экземпляры этого объекта - сравнить то, что возвращается из метода toString. Например, метод equals может выглядеть так

public boolean equals(MyObject instance)
{
   return toString().equals(instance.toString());
}

Есть ли причина не делать этого?

2 ответа

Решение

Одной из причин, чтобы избежать этого шаблона, была бы скорость: чтобы сравнить на равенство, используя toString(), вы должны сделать это:

  • Создать временный String объект для объекта this
  • Создать временный String объект для объекта instance
  • Сравните первое String ко второму String символ за символом
  • Сделать временные строки доступными для обнаружения мусора

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

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

Еще одна важная причина, чтобы избежать этой модели, связана с генеральным контрактом на toString() метод. Все переопределяемые методы класса Object имеют общий контракт. Поскольку эти методы наследуются каждым классом, который вы определяете в Java, и поскольку они так часто переопределяются во многих пользовательских классах, очень важно знать и соблюдать их общие контракты.

Генеральный контракт на toString() это самый простой из методов объекта:

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

Не требуется, чтобы строка, возвращаемая toString(), соответствовала определенному формату, а также не требуется, чтобы вы указывали формат строки, возвращаемой как часть вашего API.

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

Еще одна причина, по которой нельзя делать сравнение на основе toString() метод заключается в том, что это не предоставляет вашему классу необходимую инфраструктуру, чтобы его можно было использовать с Java Collections Framework. Классы Java Collections требуют правильной формы equals() а также hashCode() методы для объектов, хранящихся в них, для правильной работы:

  • Если есть вероятность, что класс, который вы пишете, будет использоваться в любом из классов Java Collections Framework и / или может использоваться другим программистом, то стоит написать правильную форму. equals() а также hashCode() методы.

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

Другие вопросы по тегам