这是一个相当复杂的错误,所以请耐心等待。
我在尝试编译一些 Java 代码时看到一个奇怪的错误。 编译器无法识别静态内部类。 假设我正在上一门课
MyClass
。 我需要使用的静态内部类的 FQN 为 x.y.z.Parent.DesiredClass
。 该内部类是使用其 FQN 显式导入的。 父级也使用其 FQN 导入。 现在存在另一个包含(另一个不同的 FQN)的包,它有一个类 DesiredClass
。 这个另一个 DesiredClass 位于类路径上,但没有显式导入。
在继续之前,我应该明确指出,无法更改这些类的名称。
现在,当我在代码中引用
Parent.DesiredClass
时,我使用 Parent.DesiredClass
的 FQN来避免任何可能的歧义。 但是当我编译时,当我尝试实例化
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_18x.y.z.Parent.DesiredClass
和 other DesiredClass
是使用 Microsoft Java 编译的。再次不幸的是,这些类无法用更现代版本的 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 引用它?
我们将非常感谢您的帮助。
==========
编辑:兔子洞加深了。 经过进一步调查,我发现问题是由我的路径中需要的库之一中的一行代码触发的。 我可以访问该库的源代码,但不要将其编译为我的项目的一部分。 这行代码(假设它在类
TheirClass
中)正是我想要做的;即实例化 x.y.z.DesiredClass
。 如果我删除 TheirClass
中的这行代码(但不在 MyClass
中),那么我不会收到编译错误。
因此,总而言之,以下不起作用:
MyClass.java:
x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();
他们的Class.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();
他们的Class.java:
//x.y.z.Parent.DesiredClass dc;
//dc = new x.y.z.Parent.DesiredClass();
我将尝试遵循@Richard 的建议并最小化代码,以便我可以发布它的示例。
错误消息
"an enclosing instance that contains x.y.z.Parent.DesiredClass is required"
意味着编译器认为DesiredClass
不是static
。
我建议您获取
Parent$DesiredClass.class
文件,并使用 javap
检查已编译的类属性。 这应该告诉您正在编译的类是否确实是静态内部类。
虽然仍然忙于进行@Richard 和@Stephen 建议的低级调查,但我对这个问题有一些想法。
我首先尝试使用一个名称不那么模糊的扩展
DesiredClass
,然后看看如果我更愿意使用扩展类,它是否会起作用。 它没有并导致同样的错误。
然后我尝试使用
DesiredClass
实例化 Class.forName()
:
DesiredClass dc;
try {
dc = (DesiredClass) Class.forName(classname).newInstance();
}
catch (Exception e) {
}
这有效!
虽然这有点乱,但它让我可以继续我的工作。 我很想知道错误的根本原因是什么(也许编译器使用的类加载器有一些问题,特别是考虑到有些类是用不同“品牌”的编译器编译的?),但是成本 -花更多时间试图解决这个问题的好处是不值得的。
感谢所有贡献者。
我建议尝试将这个错误减少到尽可能少的类别。
使用您的自定义代码项目,看看是否可以将有问题的类修剪为导致构建失败的一行代码。然后看看是否可以从自定义项目中删除所有其他类,但构建仍然失败。
在这个类中对方法等进行一些重命名,以隐藏生产代码的“秘密”信息,希望您将拥有一个可以在这个论坛上发布的源文件。
对正在使用的产品代码(不是 JAR 文件,其他类文件)执行相同的操作。
然后是 JAR 文件。在每个点(费力且无聊),确认您仍然遇到相同的错误。
希望可以用 3 个类文件复制这个问题,其中没有一个包含任何产品名称/代码等。将这些发布给我们看看 - 我认为这是一个有趣的问题。
ymmv