Java编译器无法识别静态内部类

问题描述 投票:0回答:3

这是一个相当复杂的错误,所以请耐心等待。

我在尝试编译一些 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_18
  • 进行编译
  • x.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 的建议并最小化代码,以便我可以发布它的示例。

java static inner-classes
3个回答
2
投票

错误消息

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

我建议您获取

Parent$DesiredClass.class
文件,并使用
javap
检查已编译的类属性。 这应该告诉您正在编译的类是否确实是静态内部类。


2
投票

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

我首先尝试使用一个名称不那么模糊的扩展

DesiredClass
,然后看看如果我更愿意使用扩展类,它是否会起作用。 它没有并导致同样的错误。

然后我尝试使用

DesiredClass
实例化
Class.forName()
:

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

}

这有效!

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

感谢所有贡献者。


1
投票

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

步骤1

使用您的自定义代码项目,看看是否可以将有问题的类修剪为导致构建失败的一行代码。然后看看是否可以从自定义项目中删除所有其他类,但构建仍然失败。

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

第2步

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

然后是 JAR 文件。在每个点(费力且无聊),确认您仍然遇到相同的错误。

第3步

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

ymmv

© www.soinside.com 2019 - 2024. All rights reserved.