【问题标题】:Java enum overriding toString()Java 枚举覆盖 toString()
【发布时间】:2011-10-13 17:55:44
【问题描述】:

我以前从未真正使用 Java 枚举类来获取常量值,过去我通常使用“public final”方法。我现在已经开始使用枚举,并且我正在重写 toString() 方法以返回与枚举名称不同的值。

我有一些 JPA 代码,我在其中创建了一个带有命名参数的 TypedQuery,其中一个是枚举值的字符串表示形式。如果我只使用 Status.ACTIVE 设置参数,我会得到正确的“A”值,但会引发异常,因为它的类型实际上是 Status 而不是 String。只有当我显式调用 toString() 方法时它才有效。我认为简单地覆盖 toString() 方法会导致返回 String 类型,无论类类型是什么。

这是枚举:

public enum Status {
    ACTIVE ("A"),
    PENDING ("P"),
    FINISHED ("F");

    private final String value;

    Status(String value) {
        this.value = value;
    }

    public String toString() {
        return value;
    }
};

这是 TypedQuery:

    TypedQuery<MechanicTimeEvent> query = entityManager().createQuery("SELECT o FROM MechanicTimeEvent o WHERE o.id.mechanicNumber = :mechanicNumber AND o.id.status = :status", MechanicTimeEvent.class);
    query.setParameter("mechanicNumber", mechanicNumber);
    query.setParameter("status", Status.ACTIVE.toString());

【问题讨论】:

  • 可以将该字段的映射添加到问题中吗?
  • 如果您正在寻找一种更简洁的编写方式,query.setParameter("status", Status.ACTIVE+""); 可以。
  • 您的@Entity 中的字段是否为Status 类型,是否用@Enumerated(EnumType.STRING) 注释?如果是这样,您应该可以在查询中使用枚举。
  • Herehere 类似的问题和答案已经讨论过了。
  • @Entity 中的字段只是一个字符串,但它只会是 A、P 或 F 的值,所以我为这些值创建了一个枚举,以便在代码中,我可以使用 Status.ACTIVE 之类的东西,它会更具描述性。我认为重写 toString() 方法以返回实际值将返回一个 String 类型,而无需显式调用 toString()。

标签: java jpa enums tostring


【解决方案1】:
public enum Status {
    ACTIVE,
    PENDING,
    FINISHED;

    @Override
    public String toString() {
        String name = "";
        switch (ordinal()) {
        case 0:
            name = "A";
            break;
        case 1:
            name = "P";
            break;
        case 2:
            name = "F";
            break;
        default:
            name = "";
            break;
        }
        return name;
    }
};

【讨论】:

  • 这个 toString() 实现需要太多的维护,特别是如果将来会添加枚举名称。最好在实例化时分配一个字符串值并返回它。
  • ... 正如问题解决方案提供的那样。该代码更具可读性,并且“字符串映射”(ACTIVE ("A"))之间的局部性也避免了运行带有拼写错误的代码(即:case 3: name = "E" 而不是case 2: name = "F")。还有,开关默认值是没有意义的。
【解决方案2】:

MechanicTimeEvent bean 的字段status 是枚举类型吗? 如果没有,我建议将其更改为枚举类型Status

你可以用@Enumerated(EnumType.STRING)注释它

此外,我建议删除枚举的值部分并 只需使用以下名称:

public enum Status {
   ACTIVE,
   PENDING,
   FINISHED;
}

【讨论】:

  • 它不是枚举类型,所以我将其更改为类型 Status 并添加了您建议的注释。我认为那成功了。现在奇怪的是,如果我的查询没有找到记录,那么它工作正常,但是如果找到记录,那么 OpenJPA 会抛出一个 ArgumentException 并告诉我检查查询的语法,不知道为什么。
  • 你是用枚举值代替字符串吗?:即query.setParameter("status", Status.ACTIVE)
  • 其实问题在于,由于数据库只存储值,即:A、P或F,那么在创建select语句时,OpenJPA将查询返回的值A传递给valueOf方法的枚举。由于它没有在枚举中找到 A,因此它会引发异常。 valueOf 方法是最终的,所以我不能覆盖它。
  • 啊,是的。也许是一个缺点,但是当将枚举与 JPA 结合使用时,只计算名称,而不是值。就我个人而言,我只会删除 value 属性并仅使用枚举的键名。看我的bjoetified回答;-)
  • 嘿lauwie,我想出了如何处理它。我最终从 OpenJPA 切换到 EclipseLink。使用 EclipseLink,我可以像没有构造函数一样简单地定义我的枚举,然后在我的实体字段中,我添加了几个 EclipseLink 注释来处理转换。检查我刚刚发布的要点。 gist.github.com/1287713
【解决方案3】:

如果我正确理解您的问题,您应该以其他方式进行枚举映射。通过这种方式,状态被存储为状态,JPA 将根据其名称 A、P、F 处理枚举。

public enum Status {
    A("ACTIVE"),
    P("PENDING"),
    F("FINISHED");

通过这种方式,您可以只将状态传递给 JPA,而无需调用 toString() 方法。将自动调用 ENUM 上的 .name() 方法来获取持久化的状态码。

【讨论】:

  • 您不应该仅仅因为这是您的数据库/无论使用什么格式,就将字段名称缩减为一个字母。你不能直接覆盖.name()吗?
  • Enum.name() 方法是最终的,所以不能被覆盖。
  • 按照我的方式进行操作的目的是,如果其他人阅读代码,Status.ACTIVE 比 Status.A 更明显。
  • 正如Java API docs 以粗体指出的那样:大多数程序员应该使用 toString()。覆盖toString() 是正确的路径。
【解决方案4】:

toString 只是 Object 中的一个普通方法,它被某些方法显式调用,例如 PrintStream.println(请记住 System.out.println),或者在使用 + 运算符连接时考虑。并非每个方法都需要实现此行为。

我建议您使用更具描述性的方法名称,例如 getValue 并显式调用它而不是覆盖 toString

【讨论】:

    【解决方案5】:

    这或者您只需为该值实现一个 getter:

    public String getValue()
    

    然后在代码中调用它:

    query.setParameter("status", Status.ACTIVE.getValue());
    

    【讨论】:

      【解决方案6】:
      java.lang.Enum said clearly:
       /**
       * Returns the name of this enum constant, exactly as declared in its
       * enum declaration.
       * 
       * <b>Most programmers should use the {@link #toString} method in
       * preference to this one, as the toString method may return
       * a more user-friendly name.</b>  This method is designed primarily for
       * use in specialized situations where correctness depends on getting the
       * exact name, which will not vary from release to release.
       *
       * @return the name of this enum constant
       */
       public final String name()
      

      就像loft 说的,你可以使用“name”的方法来获取名字。 你也可以使用 toString() 方法。

      当然它只是这个枚举常量的名称。

      【讨论】:

        猜你喜欢
        • 2012-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-19
        • 2014-03-31
        • 2017-02-11
        • 1970-01-01
        相关资源
        最近更新 更多