Действительно ли стоит реализовывать toString () для классов сущностей

Постоянно рекомендуется переопределить (реализовать) метод toString () класса.

  • В документации Java API говорится: «Это рекомендуется, чтобы все подклассы переопределяли этот метод ».
  • Блох, в Эффективная Java имеет элемент« Всегда заменять toString ». И только дурак противоречит Блоху, не так ли?

Однако я сомневаюсь в этом совете: действительно ли стоит реализовывать toString () для классов сущностей ?


Я попробую изложите мои рассуждения.

  1. Объект entity имеет уникальную идентичность; он никогда не совпадает с другим объектом, даже если два объекта имеют эквивалентные значения атрибутов. То есть (для ненулевого x ), следующий инвариант применяется к классу сущностей (по определению):

    x.equals (y) == (x == y)

  2. Метод toString () возвращает строку, которая "текстуально представляет "свой объект (в словах Java API).

  3. хорошее представление фиксирует существенную часть объекта, поэтому, если два представления различны, они являются представлениями разных (неэквивалентных) объектов , и наоборот, если два представления эквивалентны, они являются представлениями эквивалентных объектов. Это предполагает следующий инвариант для хорошего представления (для ненулевого x , y ):

    x.toString (). Equals (y.toString ()) == x.equals (y)

  4. Таким образом, для сущностей мы ожидаем equals (y) == (x == y)

  5. Метод toString () возвращает строку, которая «текстуально представляет» свой объект (в словах Java API).

  6. A хорошее представление захватывает сущность объекта, поэтому, если два представления различны, они являются представлениями разных (неэквивалентных) объектов, и наоборот, если два представления эквивалентны, они являются представлениями эквивалентных объектов. Это предполагает следующий инвариант для хорошего представления (для ненулевого x , y ):

    x.toString (). Equals (y.toString ()) == x.equals (y)

  7. Таким образом, для сущностей мы ожидаем equals (y) == (x == y)

  8. Метод toString () возвращает строку, которая «текстуально представляет» свой объект (в словах Java API).

  9. A хорошее представление захватывает сущность объекта, поэтому, если два представления различны, они являются представлениями разных (неэквивалентных) объектов, и наоборот, если два представления эквивалентны, они являются представлениями эквивалентных объектов. Это предполагает следующий инвариант для хорошего представления (для ненулевого x , y ):

    x.toString (). Equals (y.toString ()) == x.equals (y)

  10. Таким образом, для сущностей мы ожидаем поэтому, если два представления различны, они являются представлениями разных (неэквивалентных) объектов, и наоборот, если два представления эквивалентны, они являются представлениями эквивалентных объектов. Это предполагает следующий инвариант для хорошего представления (для ненулевого x , y ):

    x.toString (). Equals (y.toString ()) == x.equals (y)

  11. Таким образом, для сущностей мы ожидаем поэтому, если два представления различны, они являются представлениями разных (неэквивалентных) объектов, и наоборот, если два представления эквивалентны, они являются представлениями эквивалентных объектов. Это предполагает следующий инвариант для хорошего представления (для ненулевого x , y ):

    x.toString (). Equals (y.toString ()) == x.equals (y)

  12. Таким образом, для сущностей мы ожидаем x.toString (). Equals (y.toString ()) == (x == y) то есть каждый объект сущности должен иметь уникальное текстовое представление, которое возвращает toString () . Некоторые классы сущностей будут иметь уникальное имя или числовое поле идентификатора, поэтому их метод toString () может возвращать представление, которое включает это имя или числовой идентификатор. Но в целом метод toString () не имеет доступа к такому полю.

  13. Без уникального поля для объекта лучшее, что может сделать toString () , - это чтобы включить поле, которое вряд ли будет одинаковым для разных объектов. Но это именно то требование System.identityHashCode () , которое предоставляет Object.toString () .

  14. Итак Object.toString () подходит для объекта сущности, не имеющего элементов данных, но для большинства классов вы бы хотели включить их в текстовое представление, верно? Фактически, вы хотите включить все из них: если тип имеет (не нулевой) член данных x , вам нужно будет включить x.toString ( ) в представлении.

  15. Но это создает проблему для элементов данных, которые содержат ссылки на другие сущности: то есть ассоциации . Если объект Person имеет член данных Person Father , наивная реализация создаст фрагмент генеалогического дерева этого человека, а не самого Person . Если есть двусторонние ассоциации, наивная реализация будет рекурсивно, пока вы не получите переполнение стека Так что, может быть, пропустить элементы данных, которые содержат ассоциации?

  16. Но как насчет типа значения Брак , имеющего Мужа ] и Личность жены члены данных? Об этих ассоциациях следует сообщать с помощью Marriage.toString () . Самый простой способ заставить все методы toString () работать - чтобы Person.toString () сообщал только поля идентификации ( Person.name или ] System.identityhashCode (this) ) Person .

  17. Таким образом, похоже, что предоставленная реализация toString () на самом деле не так уж плоха для классов сущностей. В таком случае, зачем игнорировать это?


Чтобы сделать это конкретным, рассмотрите следующий код:

public final class Person {

   public void marry(Person spouse)
   {
      if (spouse == this) {
         throw new IlegalArgumentException(this + " may not marry self");
      }
      // more...
   }

   // more...
}

Насколько полезным было бы переопределение toString () при отладке исключения IlegalArgumentException , созданного Person.marry () ?

10
задан Community 23 May 2017 в 10:34
поделиться