Java 枚举 - 为啥使用 toString 而不是 name
Posted
技术标签:
【中文标题】Java 枚举 - 为啥使用 toString 而不是 name【英文标题】:Java enum - why use toString instead of nameJava 枚举 - 为什么使用 toString 而不是 name 【发布时间】:2012-10-28 18:28:15 【问题描述】:如果您在枚举 api 中查看 name()
方法,它会说:
返回此枚举常量的名称,与其枚举声明中的声明完全相同。 大多数程序员应该优先使用 toString 方法而不是这个方法, 因为 toString 方法可能会返回一个对用户更友好的名称。 此方法主要设计用于正确性取决于获取确切名称的特殊情况,该名称不会因版本而异。
为什么使用toString()
更好?我的意思是当 name() 已经是 final 时,可能会覆盖 toString。因此,如果您使用 toString 并且有人覆盖它以返回一个硬编码的值,那么您的整个应用程序就会关闭......此外,如果您查看源代码,则 toString() 方法会准确返回名称,并且只返回名称。都是一样的。
【问题讨论】:
你可以在你的枚举中覆盖toString()
,但没有其他人可以扩展和覆盖它。你不能扩展枚举。
【参考方案1】:
当您想要进行比较时使用name()
或将硬编码值用于代码中的某些内部用途。
当您想向用户(包括查看日志的开发人员)呈现信息时,请使用toString()
。永远不要在你的代码中依赖toString()
给出一个特定的值。切勿针对特定字符串对其进行测试。如果在有人正确更改 toString()
返回时您的代码中断了,那么它已经损坏了。
来自 javadoc(重点是我的):
返回对象的字符串表示形式。一般来说, toString 方法返回一个“以文本形式表示”的字符串 目的。结果应该是简洁但信息丰富的表示 这对于一个人来说很容易阅读。 建议所有 子类覆盖此方法。
【讨论】:
【参考方案2】:这真的取决于你想对返回值做什么:
如果您需要获取用于声明枚举常量的确切名称,您应该使用name()
,因为toString
可能已被覆盖
如果您想以用户友好的方式打印枚举常量,您应该使用可能已被覆盖(或未被覆盖!)的toString
。
当我觉得可能会混淆的时候,我提供了一个更具体的getXXX
方法,例如:
public enum Fields
LAST_NAME("Last Name"), FIRST_NAME("First Name");
private final String fieldDescription;
private Fields(String value)
fieldDescription = value;
public String getFieldDescription()
return fieldDescription;
【讨论】:
这是可以接受的。虽然如果他们让 enum 有一个基类,事情会更容易。【参考方案3】:name()
是enum
的“内置”方法。它是最终的,你不能改变它的实现。它在写入时返回枚举常量的名称,例如大写,没有空格等。
比较 MOBILE_PHONE_NUMBER
和 Mobile phone number
。哪个版本更易读?我相信第二个。这就是区别:name()
总是返回 MOBILE_PHONE_NUMBER
,toString()
可能被覆盖以返回 Mobile phone number
。
【讨论】:
这是不正确的!!仅当您覆盖它以返回此类值时, toString() 才会返回Mobile phone number
。否则它将返回MOBILE_PHONE_NUMBER
@spayny,很明显你必须覆盖toString()
。问题是 name()
不能被覆盖,因为它是最终的。
@AlexR 您可能需要将上述评论合并到答案中以使其 100% 正确
我同意 @artfullyContrived 的观点,因为在我阅读您的 cmets 之前,这对我来说并不明显。【参考方案4】:
name() 实际上是枚举的 java 代码中的文本名称。这意味着它仅限于可以实际出现在您的 java 代码中的字符串,但并非所有理想的字符串都可以在代码中表达。例如,您可能需要一个以数字开头的字符串。 name() 将永远无法为您获取该字符串。
【讨论】:
【参考方案5】:name() 和 toString() 不同的一个实际示例是使用单值枚举来定义单例的模式。乍一看令人惊讶,但很有意义:
enum SingletonComponent
INSTANCE(/*..configuration...*/);
/* ...behavior... */
@Override
String toString()
return "SingletonComponent"; // better than default "INSTANCE"
在这种情况下:
SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
【讨论】:
是的,你是对的......一个很好的例子是番石榴的枚举谓词【参考方案6】:虽然大多数人盲目地遵循 javadoc 的建议,但在某些非常特殊的情况下,您实际上希望避免使用 toString()。例如,我在 Java 代码中使用枚举,但它们需要序列化到数据库,然后再返回。如果我使用 toString() ,那么从技术上讲,正如其他人指出的那样,我会受到覆盖行为的影响。
此外,还可以从数据库中反序列化,例如,这应该始终在 Java 中工作:
MyEnum taco = MyEnum.valueOf(MyEnum.TACO.name());
虽然不能保证:
MyEnum taco = MyEnum.valueOf(MyEnum.TACO.toString());
顺便说一句,我发现 Javadoc 明确地说“大多数程序员应该”是很奇怪的。我在枚举的 toString 中发现很少用例,如果人们将其用作“友好名称”,这显然是一个糟糕的用例,因为他们应该使用与 i18n 更兼容的东西,在大多数情况下,使用 name() 方法。
【讨论】:
感谢您的回答。我问这个问题已经快 5 年了,我还没有使用 toString() 方法进行枚举! 99% 的情况下,我完全按照您的描述使用枚举:将枚举名称序列化和反序列化到/从数据库。 如果您通过 Web 服务与现有系统(例如大型机)集成,或者只是为现有数据库创建新的前端,您将经常使用带有连字符的枚举值。【参考方案7】:您也可以使用类似下面的代码。我使用 lombok 来避免为 getter 和构造函数编写一些样板代码。
@AllArgsConstructor
@Getter
public enum RetroDeviceStatus
DELIVERED(0,"Delivered"),
ACCEPTED(1, "Accepted"),
REJECTED(2, "Rejected"),
REPAIRED(3, "Repaired");
private final Integer value;
private final String stringValue;
@Override
public String toString()
return this.stringValue;
【讨论】:
以上是关于Java 枚举 - 为啥使用 toString 而不是 name的主要内容,如果未能解决你的问题,请参考以下文章
java如何用方法toString()将枚举类型转换为字符串类型
为啥我们在枚举中写 Integer 而不是 int? [复制]
枚举ENUM的tostring() valueof()和values()用法