【问题标题】:Java enum giving incorrect values [duplicate]Java枚举给出不正确的值[重复]
【发布时间】:2021-01-12 16:11:29
【问题描述】:

在长期使用 C、C++ 和 C# 之后,我最近开始使用 Java。我无法理解 Java 枚举应该如何工作。 经过一些研究,我创建了以下内容:

public class RedRoad implements Serializable, Parcelable
{
 // ... other parts removed for clarity
  public enum State
  {
    NOT_STARTED(0),
    PART_DONE(1),
    COMPLETED(2);
    private int value;
    private State(int value) {
        this.value = value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public int getValue() {
        return value;
    }
  }
}

我使用 getValue() 将这些 State 值作为整数存储在 sqlite 数据库中,使用 setValue() 检索它们,然后通过广播发送生成的“Road”对象。然后我这样做:

    switch (road.state) {
                case COMPLETED:
                    pline.getOutlinePaint().setColor(Color.GREEN); break;
                case PART_DONE:
                    pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00)); break;
                case NOT_STARTED:
                    default: pline.getOutlinePaint().setColor(Color.RED);
            }

但前两种情况永远不会被调用,即使我已经检查过 road.state.getValue() 有时是 1 ,而不是零。 此外,如果我将切换代码更改为:

        switch (road.state.getValue()) {
                case 2:
                    pline.getOutlinePaint().setColor(Color.GREEN); break;
                case 1:
                    Log.d("*** road state ", String.valueOf(road.state.getValue()));
                    Log.e("*** road state ", String.valueOf(road.state));
                    pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00));
                    break;
                case 0:
                default:
                    pline.getOutlinePaint().setColor(Color.RED);
            }

然后根据要求设置颜色。我在日志中得到了一个非凡的输出:

D/*** road state: 1
E/*** road state: NOT_STARTED

这怎么可能? NOT_STARTED 被定义为零!

[编辑] 后来发现,除了上述之外(我可以找到解决方法),从异步任务发送到主要活动后,值不正确('Road'类是可打包的)。如果我在发送之前记录 state.getValue() ,然后在接收之后再次记录,任何非零值都已更改为零。

【问题讨论】:

  • 我注意到你的枚举中有二传手。枚举值应该是不可变的;你应该删除那些。
  • @AndyTurner 取决于我想它们的用途。我见过枚举用作存储值的单例对象。这并不是完全错误,但“每个 JVM 一个实例”的事情确实需要谨慎
  • @JeroenSteenbeeke 这些值在规范中称为Enum Constants。它们旨在成为常量。 More here.
  • @AndyTurner 该规范还允许非最终成员,因此暗示了不变性但不是必需的。我同意在几乎所有情况下,拥有可变枚举都是一个坏主意,这正是您第二个链接中的原因。但我们都知道,我们开发人员有时会提出非正统的代码(我给出的单例示例来自 Effective Java 的第 2 版)。也就是说:您说得对,需要删除问题中的设置器。
  • @Andy Turner,好的,但是在数据库中存储和检索这些值的正确方法是什么?

标签: java android enums


【解决方案1】:

您在第二个实例中对枚举常量调用String.valueOf,它调用枚举的toString 方法。枚举的默认toString 实现返回name 字段,这使得NOT_STARTED 成为有效的返回值。

枚举本质上是具有有限实现数量的抽象类,每个实现保证每个 JVM 只存在一次。

【讨论】:

  • 谢谢,我理解你的第一段,这可以解释奇怪的日志输出。但我不明白你的第二段,我仍然不知道实现我想要做的事情的正确方法。
  • 我添加了更多信息,这有帮助吗?
【解决方案2】:

@AndyTurner 关于不使用 setter 是正确的。我现在在一个专门创建的新应用程序中做了更多的测试,setter 给出了完全不可预测的结果。 所以我使用的解决方案(用于从数据库中的“int”设置值)有点无聊

protected void setState(int i) {
    switch (i)
    {
        case 2:     state = State.COMPLETED;     break;
        case 1:     state = State.PART_DONE;     break;
        default:    state = State.NOT_STARTED;
    }
}

虽然这可行,但在我看来,部分原因是使用 Enum(而不是 int)开始。 而且,由于创建设置器(我最初的)给出了不正确的结果,我想知道为什么 Android Studio(4.1)没有给我一个警告?很高兴就这么多其他(不太重要)的事情向我发出警告。

【讨论】:

  • 有一种更简单的方法可以从 int 转换为 enum 值:State.values()[i]。这将在无效值上抛出ArrayIndexOutOfBoundsException。要将 enum 转换为 int,请使用内置的 ordinal() 方法
  • @JeroenSteenbeeke,好吧,这可能“更容易”,但你为什么昨天不建议呢?那我就不需要想出另一种方法了。另外,投下一个不正确的答案,虽然不是最佳答案,是否已经完成?
  • 我投了反对票,因为您的答案不是答案,而是您问题的延续,这应该是您原始问题的编辑。至于为什么我之前没有建议values()ordinal():我理解你的问题是“我为什么在我的日志中看到NOT_STARTED”,我回答了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 2010-12-10
  • 2012-02-08
  • 2016-08-22
  • 2016-03-05
  • 1970-01-01
相关资源
最近更新 更多