真的值得为实体类实现toString() [英] Is it really worth implementing toString() for entity classes

查看:130
本文介绍了真的值得为实体类实现toString()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

始终建议覆盖(实现)类的 toString()方法。




  • Java API文档本身表示建议所有子类覆盖此方法。

  • 有效Java 中的Bloch具有Always覆盖toString。而且只有一个傻瓜与布洛赫矛盾,对不对?



然而,我怀疑这个建议:真的值得实施 toString() 实体类







  1. 一个实体对象具有唯一的身份;它永远不会与另一个对象相同,即使两个具有相同的属性值。也就是说,(对于非空 x ),以下不变量适用于实体类(按定义):



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


  2. toString )方法返回一个字符串,以文本形式表示其对象(以Java API的语言表示)。


  3. A 良好表示捕获对象的要素,因此如果两个表示不同,则它们是不同(非等效)对象的表示,相反,如果两个表示相同,则它们是等效对象的表示。这表明以下不变量表示良好(对于非null x y ):



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


  4. x.toString()。equals(y.toString())==(x == y)
    是,每个实体对象应该有一个唯一的文本表示, toString()返回。一些实体类将具有唯一的名称或数字ID字段,因此它们的 toString()方法可能返回包含该名称或数字ID的表示。但是一般来说, toString()方法无法访问这样一个字段。


  5. 没有一个实体的唯一字段,最好的 toString()可以做的是包括一个对不同对象不太一致的字段。但这正是 System.identityHashCode() ,这是 Object.toString()提供的。


  6. 所以 Object.toString()对于没有数据成员的实体对象可以,但对于大多数课程,你想要将它们包括在文本表示中,对吗?实际上,您想要包含这些的所有:如果该类型具有(非空)数据成员 x ,则需要包含 x.toString()


  7. 但是,对于持有其他实体引用的数据成员来说,这会造成问题:也就是说,哪些是关联。如果一个 Person 对象有一个个人父亲数据成员,天真的实现将产生该人的家谱的片段,不是 Person 本身。如果有双向关系,那么一个天真的实现将递归,直到你获得堆栈溢出所以也许跳过持有的数据成员协会?


  8. 但是,价值类型婚姻 / code>和个人妻子数据成员?这些协会应该由 Marriage.toString()报告。使所有 toString()方法工作的最简单的方法是为$ code> Person.toString()仅报告身份 Person c c c>或 System.identityhashCode(this) code>。


  9. 所以似乎提供的 toString()的实现实际上是对于实体类来说不是太糟糕。在这种情况下,为什么要覆盖?







,请考虑以下代码:

  public final class Person {

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

//更多...
}

调试 toString()的覆盖是多么有用> IlegalArgumentException 由$ code抛出Person.marry()?

解决方案<点#3点3号是这个论证中的薄弱环节,实际上我并不反对。你的不变量是(重新排列)

  x.equals(y)== x.toString()。equals(y.toString )); 

我会说,而是:

  x.equals(y)→x.toString()。equals(y.toString()); 

那就是逻辑含义。如果x和y相等,它们的toString()应该相等,但是等于toString()不不一定意味着对象是相等的(想想 equals ) hashCode()关系;相等的对象必须具有相同的哈希码,但相同的哈希码可以被认为意味着对象是相等的)。



从根本上说, toString()并没有任何意义在程序化的意义上,我想你试图用它来填充它。 toString()作为记录工具最有用;你会问:覆盖 toString()的有用程度将会如何:

 抛出新的IlegalArgumentException(这个+可能不会结婚); 

我会说这是很有用的。假设您注意到日志中有很多错误,请参阅:

  IllegalArgumentException:com.foo.Person@1234ABCD无法结婚自我
IllegalArgumentException:com.foo.Person@2345BCDE不能结婚self
IllegalArgumentException:com.foo.Person@3456CDEF不能结婚自我
IllegalArgumentException:com.foo.Person@4567DEFA不能结婚自我$ b $你要做什么?b

你们根本就没有任何想法发生了什么。如果你看到:

  IllegalArgumentException:Person [Fred Smith,id = 678]不能结婚self 
IllegalArgumentException: Person [Mary Smith,id = 679]无法结婚self
IllegalArgumentException:Person [Mustafa Smith,id = 680]不能结婚self
IllegalArgumentException:Person [Emily-Anne Smith,id = 681]不能结婚自己

那么你实际上有一些机会解决发生了什么('嘿,有人试图让史密斯家族嫁给自己'),这实际上可以帮助调试等等。Java对象ID给你没有任何信息


It is consistently advised to override (implement) the toString() method of a class.

  • The Java API documentation itself says "It is recommended that all subclasses override this method.".
  • Bloch, in Effective Java has the item "Always override toString". And only a fool contradicts Bloch, right?

I am however coming to doubt this advice: is it really worth implementing toString() for entity classes?


I'll try to lay out my reasoning.

  1. An entity object has a unique identity; it is never the same as another object, even if the two entites have equivalent attribute values. That is, (for non-null x), the following invariant applies for an entity class (by definition):

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

  2. The toString() method returns a string that "textually represents" its object (in the words of the Java API).

  3. A good representation captures the essentials of the object, so if two representations are different they are representaions of different (non-equivalent) objects, and conversely if two represenations are equivalent they are representations of equivalent objects. That suggests the following invariant for a good representation (for non-null x, y):

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

  4. Thus for entities we expect x.toString().equals(y.toString()) == (x == y) that is, each entity object should have a unique textual representation, which toString() returns. Some entity classes will have a unique name or numeric ID field, so their toString() method could return a representation that includes that name or numeric ID. But in general, the toString() method does not have access to such a field.

  5. Without a unique field for an entity, the best that toString() can do is to include a field that is unlikely to be the same for different objects. But that is exactly the requirement of System.identityHashCode(), which is what Object.toString() provides.

  6. So Object.toString() is OK for an entity object that has no data members, but for most classes you would want to include them in the text representation, right? In fact, you'd want to include all of them: if the type has a (non null) data member x, you would want to include x.toString() in the representation.

  7. But this creates a problem for data members that hold references to other entities: that is, which are associations. If a Person object has a Person father data member, the naive implementation will produce a fragment of that person's family tree, not of the Person itself. If there are two-way assocaitions, a naive implementation will recurse until you get stack overflow So maybe skip the data members that hold associations?

  8. But what about a value type Marriage having Person husband and Person wife data members? Those associations ought to be reported by Marriage.toString(). The simplest way to make all the toString() methods work is for Person.toString() to report only the identity fields (Person.name or System.identityhashCode(this)) of the Person.

  9. So it seems that the provided implementation of toString() is actually not too bad for entity classes. In that case, why override it?


To make it concrete, consider the following code:

public final class Person {

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

   // more...
}

Just how useful would an override of toString() be when debugging an IlegalArgumentException thrown by Person.marry()?

解决方案

Point # 3 is the weak link in this argument, and I in fact violently disagree with it. Your invariant is (reordered)

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

I would say, rather:

x.equals(y) → x.toString().equals(y.toString()); 

That is, logical implication. If x and y are equal, their toString()s should be equal, but an equal toString() does not necessarily mean that the objects are equal (think of the equals():hashCode() relationship; equal objects must have the same hash code, but same hash code can not be taken to mean the objects are equal).

Fundamentally, toString() doesn't really have any 'meaning' in a programmatic sense, and I think you're trying to imbue it with one. toString() is most useful as a tool for logging etc; you ask how useful an overridden toString() would be given:

throw new IlegalArgumentException(this + " may not marry self");

I would say it's massively useful. Say you notice a lot of errors in your logs and see:

IllegalArgumentException: com.foo.Person@1234ABCD cannot marry self
IllegalArgumentException: com.foo.Person@2345BCDE cannot marry self
IllegalArgumentException: com.foo.Person@3456CDEF cannot marry self
IllegalArgumentException: com.foo.Person@4567DEFA cannot marry self

what do you do? You have no idea at all what's going on. If you see:

IllegalArgumentException: Person["Fred Smith", id=678] cannot marry self
IllegalArgumentException: Person["Mary Smith", id=679] cannot marry self
IllegalArgumentException: Person["Mustafa Smith", id=680] cannot marry self
IllegalArgumentException: Person["Emily-Anne Smith", id=681] cannot marry self

then you actually have some chance of working out what's going on ('Hey, someone is trying to make the Smith family marry themselves') and that may actually help with debugging etc. Java object IDs give you no information at all.

这篇关于真的值得为实体类实现toString()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆