JAVAC bug - 无法将类识别为静态(后续)

时间:2013-08-07 08:29:16

标签: java compiler-construction static javac

这是对前一个问题的跟进:

accepted answer提供了解决方法,如果找不到更好的解决方案,将会使用

这个问题将原始内容提炼成一个简单,易于复制的情况,没有专有代码。因此,这提供了原始的完整代码细节。

可悲的是,使用的java版本无法轻易更改。此问题来自传统产品支持。一次构建一个文件的奇怪路径模仿了我们产品上编写的自定义代码的构建过程,该过程是在遗留API上编写的。

道歉与长度和这篇文章的细节。


问题是:

  • 为什么java编译器无法识别给定的类是静态的
  • 为什么java编译器会坚持封闭类的实例?

这篇文章试图为原帖提供不同的细节,希望代码能证明这种奇怪的行为。

Using these steps,原始帖子被简化为一个简单的3类问题,复制了原始问题。我想知道是否有人可以对此有所了解并为我们找到的内容提供一个很好的解释。


问题是:

  1. 3个public个类,其中一个包含static类。
  2. 这些类之间的继承关系。
  3. 使用Microsoft JVC和Sun javac的组合构建(至少在1.4.2_18和1.5版本上)。
  4. 最终构建中断,抱怨static类需要一个封闭的实例,这是不正确的。
  5. 确切的构建过程已包含在批处理文件中,因此可以复制。

    下面是3个java文件的完整源代码和批处理文件。也是批处理文件的运行时输出。


    Outer.java

    package demo;
    
    public class Outer
    {
        /** this causes a problem when instantiated in Superclass and in BrokenChild **/
        public static class Static_1
        {
        }
    
        /** this causes no problem as it is not instantiated in SuperClass, only in BrokenChild **/
        public static class Static_2
        {
        }
    }
    

    SuperClass.java

    package demo;
    
    import demo.Outer;
    import demo.Outer.Static_1;
    import demo.Outer.Static_2;
    
    public class SuperClass
    {
        public void breaksBuild()
        {
            // instantiating Static_1 here prevents BrokenChild from instantiating Static_1 in a later build
            Object f = new Static_1();
        }
    
    //  public void breaksBuildIfUncommented()
    //  {
    //      Object f = new Static_2();
    //  }
    
    }
    

    BrokenChild.java

    package demo;
    
    import demo.SuperClass;
    
    import demo.Outer;
    import demo.Outer.Static_1;
    import demo.Outer.Static_2;
    
    public class BrokenChild extends SuperClass
    {
        /** method broken because Static_1 is instantiated in SuperClass */
        public void breaksBuild()
        {
            // commenting the below line allows this class to build
            Object f = new Static_1();
        }
    
        /** method works because Static_2 is not instantiated in SuperClass */
        public void buildsProperly()
        {
            // this instance can remain, since it is not instantiated in SuperClass
            Object f = new Static_2();
        }
    
    }
    

    demo.bat

    @goto start
    
    Demonstrates both a working build, and a broken build of BrokenChild.
    
    setup for both scenarios:
     - Outer is built with either JVC or JAVAC
    
    scenario #1 - BrokenChild build FAILS:
     - SuperClass is built using JVC
     - BrokenChild does not build using JAVAC
    
    scenario #2 - BrokenChild build works:
     - SuperClass is built using JAVAC
     - BrokenChild does build using JAVAC
    
    
    :start
    
    @prompt $s$s$s$s$g
    
    :: init folders
    @if exist .\build rd .\build /s /q
    @md .\build
    
    @echo ------------------------------------------------------------------------------
    @echo Build Outer using JVC or JAVAC (does not matter)
    jvc.exe /nologo /d .\build .\src\demo\Outer.java
    :: building with JAVAC still breaks the BrokenChild build
    :: javac.exe -d .\build .\src\demo\Outer.java
    @echo.
    
    @echo ------------------------------------------------------------------------------
    @echo Build SuperClass using JVC (building with JAVAC does not break the BrokenChild build)
    jvc.exe /nologo /d .\build -cp:p .\build .\src\demo\SuperClass.java
    :: building with JAVAC does not break the BrokenChild build
    :: javac.exe -d .\build -classpath .\build src\demo\SuperClass.java
    @echo.
    
    @echo ------------------------------------------------------------------------------
    @echo BrokenChild build FAILS using JAVAC
    javac.exe -d .\build -classpath .\build src\demo\BrokenChild.java
    @echo.
    
    @echo.
    @echo Show files
    dir .\build\*.class /s /b
    @echo.
    
    @echo ------------------------------------------------------------------------------
    @echo BrokenChild build WORKS using JVC
    jvc.exe /nologo /d .\build -cp:p .\build .\src\demo\BrokenChild.java
    @echo.
    
    @echo.
    @echo Show files
    dir .\build\*.class /s /b
    @echo.
    @echo ------------------------------------------------------------------------------
    
    @prompt $p$g
    @pause
    

    运行demo.bat

    的输出
    Build Outer using JVC or JAVAC (does not matter)
    
        >jvc.exe /nologo /d .\build .\src\demo\Outer.java
    
    ------------------------------------------------------------------------------
    Build SuperClass using JVC (building with JAVAC does not break the BrokenChild b
    uild)
    
        >jvc.exe /nologo /d .\build -cp:p .\build .\src\demo\SuperClass.java
    
    ------------------------------------------------------------------------------
    BrokenChild build FAILS using JAVAC
    
        >javac.exe -d .\build -classpath .\build src\demo\BrokenChild.java
    src\demo\BrokenChild.java:15: error: an enclosing instance that contains Outer.S
    tatic_1 is required
                    Object f = new Static_1();
                               ^
    
    
    Show files
    
        >dir .\build\*.class /s /b
    C:\jvc_bug\build\demo\Outer$Static_1.class
    C:\jvc_bug\build\demo\Outer$Static_2.class
    C:\jvc_bug\build\demo\Outer.class
    C:\jvc_bug\build\demo\SuperClass.class
    
    ------------------------------------------------------------------------------
    BrokenChild build WORKS using JVC
    
        >jvc.exe /nologo /d .\build -cp:p .\build .\src\demo\BrokenChild.java
    
    
    Show files
    
        >dir .\build\*.class /s /b
    C:\jvc_bug\build\demo\BrokenChild.class
    C:\jvc_bug\build\demo\Outer$Static_1.class
    C:\jvc_bug\build\demo\Outer$Static_2.class
    C:\jvc_bug\build\demo\Outer.class
    C:\jvc_bug\build\demo\SuperClass.class
    

    我相信输出使问题不言而喻。很高兴根据需要提供更多详细信息。

1 个答案:

答案 0 :(得分:2)

对我来说,它看起来像是JDK 1.4.2 / 1.5中的编译器错误。我没有看到编译器调用该错误的任何明显解释。

我尝试在Java Bugs数据库中搜索类似但无法找到的内容。但这可能意味着这是其他一些错误的另一种表现形式。

人们无法用JDK 1.6或1.7重现这一点的事实很可能意味着问题(无论是什么)已经修复了很长时间。

那么你能做些什么呢?我怀疑,很少。如果您有Oracle Java支持合同(涵盖JDK 1.4),那么您可以向他们发起支持请求并要求解释。但是(假设这个 是一个错误),他们不太可能为你提供修复。


如果你想进一步调查,我会建议一些事情(如果你还没有尝试过):

  • 更改BrokenChild课程,这样您就不会import这些课程。请通过完全限定的名称来引用它们。重复SuperClass班级......

  • 使用javap检查相关的“.class”文件,看看是否有任何意外情况。

  • 尝试使用以后的(Oracle / Sun)java编译器编译单个文件;例如旧版SuperClass较新BrokenChild反之亦然

(我怀疑其中任何一个都会显示出任何有趣的东西......但它们可能会。)


我可以说的是,我希望您/您的公司向传统平台支持此产品的人收取很多钱。