Java枚举 – 为什么使用toString而不是名称

如果你看方法name()的枚举api它说:

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

为什么最好使用toString() ? 我的意思是,当name()已经是final时,toString可能会被覆盖。 所以,如果你使用toString,而有人重写它以返回一个硬编码的值,那么你的整个应用程序就closures了。另外,如果你查看源代码,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() ,或者在你的代码中使用一些内部使用的硬编码值。

当您想要向用户呈现信息(包括查看日志的开发人员toString()时使用toString() )。 永远不要依靠toString()给出具体的值。 切勿对特定的string进行testing。 如果你的代码在有人正确地改变了toString()返回时中断了,那么它已经被破坏了。

从javadoc(重点矿):

返回对象的string表示forms。 通常,toString方法返回一个“文本表示”这个对象的string。 结果应该是一个简明但是信息丰富的表示,对于一个人来说是很容易阅读的build议所有子类重写此方法。

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

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

虽然大多数人盲目地遵循javadoc的build议,但是有一些非常特殊的情况,要真正避免toString()。 例如,我在我的Java代码中使用枚举,但是他们需要序列化到数据库,然后再回来。 如果我使用toString(),那么我将在技术上受到其他人指出的重写行为的影响。

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

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

而这不能保证:

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

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

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

当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