186

如果您查看 enum api 的方法name(),它会说:

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

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

4

7 回答 7

225

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

  • 如果您需要获取用于声明枚举常量的确切名称,则应使用name()astoString可能已被覆盖
  • 如果您想以用户友好的方式打印枚举常量,您应该使用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;
    }
}
于 2012-11-08T14:37:43.653 回答
59

name()当您想要进行比较或将硬编码值用于代码中的某些内部用途时使用。

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

来自javadoc(强调我的):

返回对象的字符串表示形式。通常,toString 方法返回一个“以文本方式表示”该对象的字符串。结果应该是一个简洁但信息丰富的表示,易于人们阅读建议所有子类重写此方法。

于 2012-11-08T14:37:37.407 回答
27

name()是 的“内置”方法enum。它是最终的,你不能改变它的实现。它返回写入时枚举常量的名称,例如大写,不带空格等。

比较MOBILE_PHONE_NUMBERMobile phone number。哪个版本更易读?我相信第二个。这就是区别:name()总是返回MOBILE_PHONE_NUMBERtoString()可能被覆盖为返回Mobile phone number

于 2012-11-08T14:41:06.880 回答
17

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

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

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

而这不能保证:

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

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

于 2017-03-17T03:06:21.177 回答
7

当 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
于 2016-03-11T22:44:43.893 回答
5

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

于 2015-08-07T21:05:46.213 回答
2

您也可以使用类似下面的代码。我使用 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;
    }
}
于 2019-06-26T20:09:41.433 回答