【问题标题】:Why is the last enum in an array of all enum values created in the enum constructor null?为什么在枚举构造函数中创建的所有枚举值数组中的最后一个枚举为空?
【发布时间】:2017-09-12 17:38:43
【问题描述】:

我知道为了正确迭代枚举,你应该这样做

for (Days day : Days.values() {}

我在工作日和周末的枚举 Days 中创建了 static 数组。我通过在构造函数中执行 = new Days[] {SAT, SUN} 来使用适当的 Days 值填充它们。当我迭代它们时,它们会按预期工作。

但是,当我为 Days 的所有值创建自己的静态数组时,我迷失了 - 以与以前完全相同的方式添加它们。遍历此数组后,令我惊讶的最后一个元素是null。无论 Days 枚举中有多少元素——我开始添加更多虚构的日子来测试——结果都是一样的。 “解决方案”是使其成为final。但是我想了解我做错了什么。

这告诉我在枚举构造函数中初始化数组是不好的。我的工作日/周末数组会受到类似的影响吗?这实际上是一个很大的禁忌吗?在枚举构造函数中不应该做哪些其他事情?或者更准确地说,它应该用来做什么?除了做这样的事情

enum Days {
  MON("Monday");

  String fullname;

  private Days(String n) {fullname = n};
}

有人可以指出任何可以解释这一点的文档吗?我可能缺少一些关于 Java 枚举和/或其构造函数的明显信息。

在寻找答案的过程中,我找到了static {}——就枚举中此类静态数组的初始化而言,这是否是一种好习惯?还有其他选择吗?

编辑:因为需要准确的代码。

public enum Days {
  MON, TUE, WED, THU, FRI, SAT, SUN;

  public static Days[] weekdays;
  public static Days[] weekend;
  public static Days[] all;

  Days() {
    weekdays = new Days[] {MON, TUE, WED, THU, FRI};
    weekend = new Days[] {SAT, SUN};
    all = new Days[] {MON, TUE, WED, THU, FRI, SAT, SUN};
  }
}

String s = ""
for (Days d : Days.all) {
  s += d.toString(); //d is null once it reaches the last item 
}

【问题讨论】:

  • 不要描述你的代码。发表它。不要描述或解释你得到的错误。发布它们。
  • 你能分享初始化所述数组的代码吗?
  • 您能否发布导致问题的代码(并从您的问题中删除一些文本[即总结一点])?
  • 这段代码甚至不应该编译:ideone.com/nRyo27。 Makoto 的回答解释了原因,但您的问题表明您正在运行它。似乎您正在运行无法编译的代码(我知道某些 IDE 允许这样做),或者您的实际代码不同。

标签: java enums constructor initialization


【解决方案1】:

试试:

public enum Days {
    MON, TUE, WED, THU, FRI, SAT, SUN;

    public static Days[] weekdays = {MON, TUE, WED, THU, FRI};
    public static Days[] weekend = {SAT, SUN};
    public static Days[] all = {MON, TUE, WED, THU, FRI, SAT, SUN};
}

您的代码没有在我的 Eclipse IDE 中编译。你的代码试图做的是:

  • 定义一个包含 7 个实例的枚举 MON, TUE, WED, THU, FRI, SAT, SUN(这是第一行)。
  • 当任何 Days 实例被创建时,您将使用特定内容填充三个静态数组(这就是您的构造函数所做的) - 这就是问题所在!当您正在实例化时,例如第一个枚举实例(将成为MON),其他的甚至还没有开始它们的生命周期,甚至MON 还没有准备好(并且还没有以该名称可用)。所以数组会得到一些未定义/空的内容。
  • 由于您的枚举包含 7 个值,因此您需要对数组进行 7 次初始化,每次都有一个可用的实例。最后一个实例是 SUN。然后其他 6 个实例都准备好了,你第七次覆盖你的数组。这次只丢失了SUN,这就是为什么最后一个条目仍然为空的原因。

所以,不要在这个枚举本身的构造函数中引用枚举值。

顺便问一下,您使用的哪个编译器没有标记编译时错误?

【讨论】:

  • 我在 android 上使用 AIDE IDE,显然它不符合 java 标准,因为它是 android sdk?我不知道具体情况。但是,为什么最后一项为空的解释是正确的,所以我接受这个作为主题中问题的答案。我很想听听一些关于如何正确初始化我的数组的建议(即使是我自己提出的几个选项)。谢谢。
  • 我在答案中给出的代码完美运行(至少在桌面 Java 中)。
  • 它确实对我有用。如果这是最佳实践(或其中之一),则必须这样做。
【解决方案2】:

据我所见,你被JLS 8.9.2烧死了。

从构造函数、实例初始化程序块或实例变量初始化程序表达式引用不是常量变量(第 4.12.4 节)的枚举类型的静态字段是编译时错误。

由于枚举值为themselves static,因此您的代码违规。

虽然它可能看起来效率低下,但您可以做的是设置您的 getter 以缓存有关您的周末枚举的信息一次,以便您以后可以参考它们。

public Days[] getWeekend() {
    if(null == weekend) {
        weekend = new Days[]{MON, TUE};
    }
    return weekend;
}

我将处理并发问题的问题留给读者作为练习。

【讨论】:

  • 编译时错误?它编译得很好,它在运行时崩溃。我添加了一些代码。这仍然是原因吗?
  • @Raith:你运行的是什么版本的 Java?带有 IntelliJ 的 Java 8 拒绝编译此错误:(11, 42) 从初始化程序对静态字段的非法引用。
  • 我正在使用适用于 android 的 AIDE IDE,有趣的是它没有指定它是什么 java 版本。我正在搜索,但它应该等于7。我说等价是因为它实际上是android sdk。不能说比这更具体的了。但你是对的,这不能在我的桌面上用 Eclipse 和 Java 7 编译。我的错。
猜你喜欢
  • 2021-09-11
  • 2011-08-20
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 2020-10-28
相关资源
最近更新 更多