6

这是一个相当复杂的错误,所以请多多包涵。

我在尝试编译一些 Java 代码时看到一个奇怪的错误。编译器无法识别静态内部类。假设我正在上课MyClass。我需要使用的静态内部类的 FQN 为x.y.z.Parent.DesiredClass. 这个内部类是使用其 FQN 显式导入的。还使用其 FQN 导入父级。现在存在另一个带有(另一个,不同的 FQN)的包,它有一个类DesiredClass。这个其他的 DesiredClass 在类路径上,但它没有被显式导入。

在我继续之前,我应该明确指出无法更改这些类的名称。

现在,当我Parent.DesiredClass在代码中引用时,我使用FQNParent.DesiredClass避免任何可能的歧义。但是当我编译时,当我尝试实例化Parent.DesiredClass. 我的代码片段:

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

这会产生以下编译时错误:

MyClass.java:123: an enclosing instance that contains x.y.z.Parent.DesiredClass is required
   dc = new x.y.z.Parent.DesiredClass();
           ^

需要注意的是,链接到的类是用不同的 Java 编译器编译的:

  • MyClass旨在使用 Sun Java 1.4.2_18 编译
  • x.y.z.Parent.DesiredClass另一个是使用 Microsoft JavaDesiredClass编译的。

同样,不幸的是,这些类不能用更现代的 Java 版本重新编译。

此外,当实际尝试使用 Sun Java 1.4.2_18 进行编译时,编译器中会出现以下异常:

An exception has occurred in the compiler (1.4.2_18). Please file a bug at the Java Developer Connection (http://java.sun.com/cgi-bin/bugreport.cgi)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java.lang.NullPointerException
        at com.sun.tools.javac.v8.code.Type.isSubTypes(Type.java:557)
        at com.sun.tools.javac.v8.comp.Resolve.instantiate(Resolve.java:221)
        at com.sun.tools.javac.v8.comp.Resolve.selectBest(Resolve.java:317)
        at com.sun.tools.javac.v8.comp.Resolve.findMethod(Resolve.java:414)
        ...
        at com.sun.tools.javac.v8.comp.Attr.attribClass(Attr.java:1332)
        at com.sun.tools.javac.v8.JavaCompiler.compile(JavaCompiler.java:355)
        at com.sun.tools.javac.v8.Main.compile(Main.java:569)
        at com.sun.tools.javac.Main.compile(Main.java:36)
        at com.sun.tools.javac.Main.main(Main.java:27)
Error encountered running Java Compiler

Aborting compilation.

如果我使用较新版本的 Java(1.5 及以上)进行编译,则不会出现编译器异常,但仍会出现上述错误。

谁能解释一下这个错误?为什么编译器不将静态内部类识别为静态,即使它是使用其 FQN 引用的?

对你的帮助表示感谢。

==========

编辑:兔子洞加深了。经过进一步调查,我发现问题是由我需要在我的路径中的一个库中的一行代码触发的。我可以访问这个库的源代码,但不要将它编译为我的项目的一部分。这行代码(假设它在 classTheirClass中)正是我想要做的;即,实例化x.y.z.DesiredClass. TheirClass如果我在(而不是)中删除这行代码MyClass,那么我不会收到编译错误。

因此,总而言之,以下内容不起作用

MyClass.java

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

他们的类.java

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

以下确实有效:

MyClass.java

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

他们的类.java

//x.y.z.Parent.DesiredClass dc;
//dc = new x.y.z.Parent.DesiredClass();

我将尝试遵循@Richard 的建议并最小化代码,以便我可以发布它的示例。

4

3 回答 3

2

错误消息"an enclosing instance that contains x.y.z.Parent.DesiredClass is required"意味着编译器认为DesiredClass不是static

我建议您掌握该Parent$DesiredClass.class文件,并使用它javap来检查编译后的类属性。这应该告诉你你正在编译的类是否真的是一个静态内部类。

于 2013-06-25T15:50:28.277 回答
2

在忙于进行@Richard 和@Stephen 建议的低级别调查时,我对这个问题有一些想法。

我首先尝试DesiredClass使用名称不那么含糊的名称进行扩展,然后看看如果我宁愿使用扩展类,它是否可以工作。它没有并导致同样的错误。

然后我尝试使用实例DesiredClassClass.forName()

DesiredClass dc;
try {
    dc = (DesiredClass) Class.forName(classname).newInstance();
}
catch (Exception e) {

}

这行得通!

尽管这有点混乱,但它让我可以继续我的工作。我很想知道错误的根本原因是什么(编译器使用的类加载器可能存在一些问题,特别是考虑到有些类是用不同“品牌”的编译器编译的?),但是成本-花更多时间试图弄清楚这一点的好处是不值得的。

感谢所有做出贡献的人。

于 2013-06-27T14:38:15.923 回答
1

我建议尝试将此错误减少到尽可能少的类。

步骤1

以您的自定义代码项目为例,看看您是否可以将有问题的类缩减为无法构建的单行代码。然后看看您是否可以从您的自定义项目中删除所有其他类,并且仍然无法构建。

在这个单一的类中对方法等进行一些重命名,以隐藏生产代码的“秘密”信息,希望你有一个可以在这个论坛上发布的源文件。

第2步

对正在使用的产品代码(不是 JAR 文件,其他类文件)执行相同的操作。

然后是 JAR 文件的东西。在每一点(费力和无聊),确认你仍然得到同样的错误。

第 3 步

希望可以用 3 个类文件复制这个问题,这些文件都不包含任何生产名称/代码等。发布这些给我们看 - 我认为这是一个有趣的问题。

ymmv

于 2013-06-26T09:41:39.413 回答