提问人:Raedwald 提问时间:2/4/2011 最后编辑:CommunityRaedwald 更新时间:3/31/2016 访问量:11920
真的值得为实体类实现 toString() 吗
Is it really worth implementing toString() for entity classes
问:
始终建议重写(实现)类的方法。toString()
- Java API 文档本身说“建议所有子类都覆盖此方法”。
- Bloch,在 Effective Java 中有“Always override toString”项。只有傻瓜才会反驳布洛赫,对吧?
然而,我开始怀疑这个建议:它真的值得为实体类实现吗?toString()
我会试着列出我的推理。
实体对象具有唯一标识;它永远不会与另一个对象相同,即使两个实体具有等效的属性值。也就是说,(对于非 null x),以下不变量适用于实体类(根据定义):
x.equals(y) == (x == y)
该方法返回一个字符串,该字符串“以文本方式表示”其对象(用 Java API 的话来说)。
toString()
一个好的表示抓住了对象的本质,所以如果两个表示不同,它们就是不同(不等价)对象的表示,反之,如果两个表示是等价的,它们就是等价对象的表示。这表明以下不变量对于良好的表示(对于非空 x, y):
x.toString().equals(y.toString()) == x.equals(y)
因此,对于我们期望的实体,即每个实体对象都应该有一个唯一的文本表示,该表示形式返回。某些实体类将具有唯一的名称或数字 ID 字段,因此它们的方法可以返回包含该名称或数字 ID 的表示形式。但一般来说,该方法无法访问这样的字段。
x.toString().equals(y.toString()) == (x == y)
toString()
toString()
toString()
如果没有实体的唯一字段,最好的办法是包含一个对于不同对象不太可能相同的字段。但这正是
System.identityHashCode()
的要求,它提供了。toString()
Object.toString()
因此,对于没有数据成员的实体对象来说,这是可以的,但对于大多数类,您希望将它们包含在文本表示中,对吗?事实上,您需要包含所有这些:如果类型具有(非 null)数据成员 x,则希望包含在表示中。
Object.toString()
x.toString()
但是,这会给持有对其他实体的引用的数据成员带来问题:即关联。如果一个对象有一个数据成员,那么朴素的实现将生成该人的家谱的片段,而不是它本身的片段。如果存在双向关联,则幼稚的实现将递归,直到堆栈溢出 所以也许跳过持有关联的数据成员?
Person
Person father
Person
但是,具有和数据成员的值类型呢?这些关联应由 .使所有方法都起作用的最简单方法是仅报告 的标识字段 ( 或 )。
Marriage
Person husband
Person wife
Marriage.toString()
toString()
Person.toString()
Person.name
System.identityhashCode(this)
Person
因此,对于实体类来说,提供的实现实际上还不错。既然如此,为什么要覆盖它呢?
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()
答:
因此,似乎提供的 toString() 实现实际上对于实体类来说还不错。既然如此,为什么要覆盖它呢?
是什么让你认为目标只是拥有一个唯一的字符串?那不是它的目的。它的目的是为您提供有关实例的上下文,而仅凭类名和哈希码并不能为您提供上下文。toString()
编辑
我只想说,我绝不认为您需要覆盖每个对象。无值对象(如侦听器或策略的具体实现)不需要重写,因为每个实例都无法与其他实例区分开来,这意味着类名就足够了。toString()
toString()
评论
IlegalArgumentException
toString()
在实体类中拥有方法对于调试目的非常有帮助。从实用的角度来看,使用 IDE 模板或类似 Project Lombok 注解的东西可以大大简化这一点,并使其易于快速实现。toString()
@ToString
评论
toString()
x.equals(y)
x==y
toString()
x==y
Object.toString()
我总是出于我自己的目的使用 toString(),而不是因为某些技术要求。当我有一个 Person 类时,toString 方法返回该人的名字。不多也不少。它不是唯一的,但出于调试目的,它足以看出人的意思。特别是在 Web 开发中,当我只需要在 JSP 中编写对象名称即可获得人名时,这非常方便,这样我就知道我有正确的对象。
如果对象有一些唯一的数据(如数据库 ID),那么这是 toString() 的完美候选者,因此它可以返回 .但唯一性不是必需的。#294: John Doe
真。。。就算布洛赫先生这么说......我认为有任何实现 toString() 的规则是没有意义的。它对 hashCode() 和 equals() 有意义,但对 toString() 没有意义。
是的,这是值得的。ToString 有助于为对象的状态提供有形的可视化输出。IMO,这在实体中尤为重要,因为 ORM 或其他第三方库经常打印对象作为其日志记录策略的一部分。
logger.debug("Entity: {}", entity);
显然会隐式调用 toString()。
它一次又一次地帮助我直观地查看实体的状态,以确定它在事务性和一般调试方面在日志记录中是暂时的还是持久的。
你更愿意看到这个吗:
DEBUG | pattern: test.entity.MyEntity@12345f
或者这个:
DEBUG | pattern: MyEntity [id = 1234.0, foo=bar, bar=baz]
简而言之,你不会重写 toString 的唯一原因是懒惰。在最近的版本中,Eclipse 甚至有一个 toString 生成器!
评论
点 #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()
throw new IlegalArgumentException(this + " may not marry self");
我会说它非常有用。假设您发现日志中出现很多错误,并看到:
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
你是做什么工作的?你根本不知道发生了什么。如果看到:
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
那么你实际上有机会弄清楚发生了什么(“嘿,有人试图让史密斯一家结婚”),这实际上可能有助于调试等。Java 对象 ID 根本不会为您提供任何信息。
评论
toString()
Person.name
x.equals(y) == (x == y)
是这里实体的定义。
上一个:未来与单声道的区别
下一个:是否应该报告异常的消息文本?
评论