Java枚举-为什么使用toString而不是name

Java枚举-为什么使用toString而不是name,java,enums,Java,Enums,如果查看enum api中的方法,它会说: 返回此枚举常量的名称,与在其枚举声明中声明的名称完全相同。 大多数程序员应该优先使用toString方法, 因为toString方法可能会返回一个更为用户友好的名称。 此方法主要设计用于特定情况,其中正确性取决于获得确切的名称,不同版本的名称不会有所不同 为什么使用toString()更好?我的意思是,当name()已经是final时,toString可能会被重写。因此,如果您使用toString,而有人覆盖它以返回硬编码值,则整个应用程序都将关闭。。

如果查看enum api中的方法,它会说:

返回此枚举常量的名称,与在其枚举声明中声明的名称完全相同。 大多数程序员应该优先使用toString方法, 因为toString方法可能会返回一个更为用户友好的名称。 此方法主要设计用于特定情况,其中正确性取决于获得确切的名称,不同版本的名称不会有所不同

为什么使用
toString()
更好?我的意思是,当name()已经是final时,toString可能会被重写。因此,如果您使用toString,而有人覆盖它以返回硬编码值,则整个应用程序都将关闭。。。此外,如果您查看源代码,toString()方法将准确且仅返回名称。这是一样的。

当您想要进行比较或在代码内部使用硬编码值时,请使用
name()

当您想向用户(包括查看日志的开发人员)提供信息时,请使用
toString()
。千万不要在代码中依赖于
toString()
给定特定值。永远不要针对特定字符串进行测试。如果您的代码在有人正确更改
toString()
返回时中断,那么它已经中断

从javadoc(我的重点):

返回对象的字符串表示形式。总的来说 toString方法返回一个字符串,该字符串在文本上表示该字符串 对象结果应该是简洁但信息丰富的表示 这对一个人来说很容易阅读建议所有 子类重写此方法。


这实际上取决于您想对返回值做什么:

  • 如果需要获取用于声明枚举常量的确切名称,则应使用
    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;
    }
}
name()
enum
的“内置”方法。它是最终的,您不能更改它的实现。它在写入时返回枚举常量的名称,例如大写,不带空格等


比较
手机号码
手机号码
。哪个版本更可读?我相信第二个。这就是区别:
name()
总是返回
MOBILE\u PHONE\u NUMBER
toString()
可能会被覆盖以返回
MOBILE PHONE NUMBER

name()实际上是枚举的java代码中的文本名称。这意味着它仅限于可以实际出现在java代码中的字符串,但并非所有需要的字符串都可以在代码中表达。例如,您可能需要一个以数字开头的字符串。name()永远无法为您获取该字符串。

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

虽然大多数人盲目地遵循javadoc的建议,但在一些非常特殊的情况下,您实际上希望避免使用toString()。例如,我在Java代码中使用枚举,但它们需要序列化到数据库,然后再返回。如果我使用toString(),那么从技术上讲,我会像其他人指出的那样,受到重写行为的影响

此外,还可以从数据库反序列化,例如,这应该在Java中始终有效:

MyEnum taco=MyEnum.valueOf(MyEnum.taco.name())

鉴于不保证:

MyEnum taco=MyEnum.valueOf(MyEnum.taco.toString())


顺便说一句,我发现Javadoc明确地说“大多数程序员应该这样做”是非常奇怪的。我发现在枚举的toString中很少有用例,如果人们使用它作为“友好的名称”,这显然是一个糟糕的用例,因为他们应该使用与i18n更兼容的东西,在大多数情况下,这将使用name()方法。

您也可以使用类似下面的代码。我使用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;
    }
}

这是不对的!!toString()仅当覆盖它以返回该值时才返回移动电话号码。否则它将返回
MOBILE\u PHONE\u NUMBER
@spayny,显然您必须重写
toString()
。问题是,
name()
不能被覆盖,因为它是最终的。@AlexR您可能需要在答案中加入您的上述注释,使其100%正确。我同意@artfullyContrived,因为在我阅读您的注释之前,它对我来说并不明显。是的,您是对的。。。一个很好的例子是Guava的枚举谓词。您可以在枚举中重写
toString()
,但其他人无法扩展和重写它。您无法扩展枚举。谢谢您的回答。我问这个问题已经快5年了,我还没有对枚举使用toString()方法!99%的情况下,我使用枚举的目的与您描述的完全相同:将枚举名称序列化和反序列化到数据库中或从数据库中序列化。如果您通过Web服务与现有系统(如大型机)集成,或只是为现有数据库创建一个新的前端,则经常会使用带有连字符的枚举值。这是可以接受的。虽然如果他们让enum有一个基类,事情会更容易。