【问题标题】:Reference to Public Enum results in Anonymous Class对公共枚举的引用导致匿名类
【发布时间】:2009-12-28 18:02:31
【问题描述】:

我在编译时得到了一个我没想到的匿名类。相关代码如下,再详细解释:

CircuitType.java 的整体:

public enum CircuitType { V110A20, V110A30, V208A20, V208A30 }

来自 Auditor.java,第 3-9 行:

public class Auditor {
    private String[] fileNames;
    private int numV110A20;
    private int numV110A30;
    private int numV208A20;
    private int numV208A30;

来自 Auditor.java,第 104-121 行:

[...]
switch (newCircuit.getType()) {
    case V110A20:
        this.numV110A20++;
        break;
    case V110A30:
        this.numV110A30++;
        break;
    case V208A20:
        this.numV208A20++;
        break;
    case V208A30:
        this.numV208A30++;
        break;
    default:
        System.err.println("An Error Has Occured.");
        System.exit(-1);
        break;
}
[...]

来自 Circuit.java,第 1-5 行:

public class Circuit {
    private CircuitType myType;
    public CircuitType getType() {
        return this.myType;
    }
[...]

当命令时

javac *.java

执行后,会生成一个匿名类 Auditor$1.java。显然,这些文件都在一个文件系统目录中并排放置,其中不包含任何其他内容。

当注释掉第 104-121 行时,不会生成匿名类。

我一开始以为是包的问题,​​所以把这三个类放在一个包里,但是我对包的了解还不够,无法让它工作。如果这真的是一个包裹问题,有人可以指导我准确地标记它们吗?不过,如果不需要的话,我宁愿不必打包它们。

匿名类是一个问题的原因,除了这些类通常表示命名空间问题之外,它破坏了我用于自动编译的 Makefile。

更新


附件是一个控制台会话,我希望它可以揭示这个谜团:

% javap 'Auditor$1'
Compiled from "Auditor.java"
class Auditor$1 extends java.lang.Object{
    static final int[] $SwitchMap$CircuitType;
    static {};
}

【问题讨论】:

  • 不幸的是,我无法解决这个问题,但 +1 发布了一个非常明确的问题。
  • 这可能不是您想听到的答案,但make 并不是真正适合Java 开发的工具。我强烈建议改用ant。随着您开发更复杂的应用程序,您将到处都有匿名类,这是正确的。
  • 我有兴趣了解更多 Auditor.java。根据你在这里所说的,我很难相信 Circuit.java 是问题所在。
  • 根据您的要求,我包含了更多的 Auditor.java。
  • 如果您发布完整的代码,StackOverflow 可能不会爆炸。另一方面,欢迎您将您的代码通过电子邮件发送给我。 myFirstName.myLastName@gmail.com .

标签: java switch-statement enums anonymous anonymous-class


【解决方案1】:

我已经着手构建了一个小项目,其中包含您发布的源代码以及围绕它的足够框架以使其编译。我得到了 3 个类文件:Circuit.class、CircuitType.class 和 Auditor.class - 正如预期的那样。

所有这些都在 Java 1.6 下。 但正如其他人所指出的,我认为你对问题的诊断是错误的。

匿名类很容易意外生成:通常是这样的构造

Circuit myCircuit = new Circuit() {
   public CircuitType getCircuitType() {
      return XXX;
   }
}
例如,

将创建一个。鉴于您的代码更多,优秀的 SO 人员可能能够查明您的错误。

使用javap 或更好的“真正的”Java 反汇编程序(如JD)来反汇编您的类文件可能会很有趣且具有启发性。


更新

将您的新审核员代码添加到我的...没有变化。没有匿名类。

您的代码当然是正确的(在我们可以看到的范围内),但设计不是很OO。有些人会指出,每次出现新的电路类型时,您都必须扩展您的计数器声明和 switch 语句。

您也没有充分利用枚举的“特殊功能”。我有你的Auditor 方法的简化版本:

   private int[] counters = new int[CircuitType.values().length];

   public void tallySomething() {
      Circuit newCircuit = new Circuit();
      counters[newCircuit.getType().ordinal()]++;
  }

更新 2

我发现您的 javap 输出很有启发性。请参阅下面的评论。

我的结论:

  1. 是的,显然您的 Java 实现正在使用匿名类进行切换。蹩脚,但合法。
  2. 您有以下选择:
    • 消除switch
    • 使用不同的 Java 实现
    • 与匿名班级一起生活;抛弃 make 并使用 ant 来接受 Java 的匿名类和其他奇怪之处。

由于您只是因为非标准编译设置而遇到问题,因此我将采用最后一种解决方案并在那里解决问题。

【讨论】:

  • 根据您的要求,我包含了来自 Auditor.java 的更多代码。第 104-121 行代码块肯定是罪魁祸首,因为在注释掉该代码块时不会生成匿名类。我相信我已经包含了与该代码块相关的所有内容。如果您还需要什么,请告诉我。
  • 我的心都碎了。两次。用switch语句肯定有我的匿名类,注释掉switch语句时肯定没有匿名类。当您说您仍然没有获得匿名类时,我将代码从我的 UNIX 开发环境移动到带有最新 JDK 更新并重新编译的一次性 Windows 虚拟机。我仍然得到一个带有 switch 语句的匿名类,没有。
  • 您的统计方法也令人惊讶。我正在用你的方法重写我的开关,既是因为它更好,也是为了看看它是否可以解决匿名类问题。
  • @Carl:我已经用“javap”的输出更新了我的问题。虽然我以前从未使用过'javap',甚至在你提到它之前都不知道它,但输出似乎与 switch 语句的性质有关。但是,我无法进一步预测任何事情。也许你可以?
  • 是的...... javap 确实很有趣。显然,您的特定 Java 实现使用这个匿名类来实现 switch-on-enum 功能。要意识到的是,java switch 语句实际上只“执行”ints。大多数这些很酷的新语言特性只是“基本”Java 的语法糖。似乎 switch 语句是通过在映射中查找枚举然后打开存储为值的 int 来实现的。
【解决方案2】:

确实似乎(至少在某些情况下)将为 switch 语句生成一个内部类:

Java enum and additional class files

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多