参考公共枚举导致匿名类问题

13

我在编译时得到了一个匿名类,但我并没有预期这个结果。下面是相关代码,然后是更详细的解释:

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
很遗憾,我无法帮助您解决这个问题,但是我会点赞,因为你提出了一个非常清晰明了的问题。 - Topher Fangio
1
这可能不是你想听到的答案,但make并不是一个适合Java开发的工具。我强烈建议使用ant代替。随着你开发更复杂的应用程序,你会在各个地方都有匿名类,这是正确的做法。 - Carl Smotricz
如果你发布了完整的代码,StackOverflow可能不会爆炸。另一方面,欢迎通过电子邮件发送你的代码给我。我的邮箱是myFirstName.myLastName@gmail.com - Carl Smotricz
更新了我的回答并添加了一条新评论。 - Carl Smotricz
可能是 https://dev59.com/wnI-5IYBdhLWcg3weoPR 的重复问题。 - Brad Cupit
显示剩余3条评论
2个回答

4
我已经建立了一个小项目,其中包含您发布的源代码,以及足够的框架使其编译。我得到了3个类文件:Circuit.class、CircuitType.class和Auditor.class - 正如预期的那样。
所有这些都在Java 1.6下完成。但是正如其他人所指出的,我认为您对问题的诊断是错误的。 匿名类很容易意外生成:通常像这样的结构
Circuit myCircuit = new Circuit() {
   public CircuitType getCircuitType() {
      return XXX;
   }
}
例如,将创建一个。如果提供更多的代码,好的SO人员可能能够确定您的错误。

使用javap或更好的“真正的”Java反汇编器(如JD)来反汇编您的类文件可能很有趣且富有教育意义。


更新

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

您的代码当然是正确的(就我们所看到的而言),但设计不是很面向对象。有些人会指出,每次出现新电路类型时,您都必须扩展计数器声明和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实现正在使用匿名类进行switch。不太好,但合法。
  2. 您有以下选项:
    • 消除switch
    • 使用其他Java实现
    • 接受匿名类,放弃make并使用ant来接受Java中其他奇怪之处。

由于您只有因为非标准编译设置而遇到问题,所以我建议您选择最后一个解决方案并在那里解决问题。


根据您的要求,我在Auditor.java中包含了更多的代码。104-121行的代码块肯定是罪魁祸首,因为当该代码块被注释掉时,匿名类不会生成。我相信我已经包含了与该代码块相关的所有内容。如果您需要其他任何东西,请告诉我。 - Maarx
我的头脑已经被炸了,两次。当使用 switch 语句时,肯定会有一个匿名类与我相关,而当注释掉 switch 语句时,肯定没有匿名类。当你说你仍然没有得到匿名类时,我将代码从我的 UNIX 开发环境移动到一个临时的 Windows 虚拟机,并重新编译了一遍。我仍然可以在 switch 语句中得到匿名类,而在没有 switch 语句的情况下则没有。 - Maarx
@Carl:我已经使用'javap'更新了我的问题。虽然我以前从未使用过'javap',甚至在你提到它之前都不知道它的存在,但输出似乎与switch语句的性质有着明显的关联。然而,我无法进一步推断出任何信息。也许你可以帮忙吗? - Maarx
1
是的... javap 确实很有趣。显然,您特定的 Java 实现使用此匿名类来实现 switch-on-enum 功能。需要认识到的是,Java 的 switch 语句实际上只处理 int。大多数这些新颖的语言特性只是“基本”Java的语法糖。似乎 switch 语句是通过在映射中查找枚举值,然后切换存储为值的 int 来实现的。 - Carl Smotricz
出于好奇,你使用的是哪个Java实现,它不会为switch创建匿名类?我认为,在预装Windows Vista的HP Compaq Core2 vPro上安装最新版JDK直接从Sun网站下载,这应该是最标准的实现方式,但我仍然得到了一个匿名类。 - Maarx
显示剩余2条评论

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接