Search code examples
javastatic-methodsunchecked-exception

Unchecked exception when using static imports, how come?


I'm experiencing some strange behavior when using static imports of inherited static methods:

com/example/util/BaseUtil.java:

package com.example.util;

/*default*/ class BaseUtil {
    public static final void foo(){ System.out.println("foo"); }
}

com/example/util/Util.java:

package com.example.util;

public final class Util extends BaseUtil{
    public static void bar(){ System.out.println("bar"); }
    //foo() will be inherited
}

com/example/UtilTest.java

package com.example;

import static com.example.util.Util.bar;
import static com.example.util.Util.foo;

public class UtilTest {
    public static void main(String[] args) {
        bar();
        foo();
    }
}

Running UtilTest result in an unchecked exception!

Exception in thread "main" java.lang.IllegalAccessError: tried to access class com.example.util.BaseUtil from class com.example.UtilTest

    at com.example.UtilTest.main(UtilTest.java:15)

However, if I were to reference the methods via Util (without static imports) everything works as expected:

com/example/UtilTest.java

package com.example;

import com.example.util.Util;

public class UtilTest {
    public static void main(String[] args) {
        Util.bar();
        Util.foo();
    }
}

So, what gives?


Solution

  • /*default*/ class BaseUtil { //only visible within the package com/example/util
    

    That class has defualt access specifier, which makes it invisible from outside of that package.

    You need to make it public.

    Update

    Following is how the decompilation looks like:

    public class com.example.UtilTest extends java.lang.Object{
    public com.example.UtilTest();
      Code:
       0:   aload_0
       1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
       4:   return
    
    public static void main(java.lang.String[]);
      Code:
       0:   invokestatic    #16; //Method com/example/util/Util.bar:()V
       3:   invokestatic    #21; //Method com/example/util/BaseUtil.foo:()V
       6:   return
    
    }
    

    And the following is what I get by using JD GUI

    package com.example;
    
    import com.example.util.BaseUtil;
    import com.example.util.Util;
    
    public class UtilTest
    {
      public static void main(String[] args)
      {
        Util.bar();
        BaseUtil.foo();
      }
    }
    

    which of course is not going to compile.

    Looks like a hole in the compiler (may be due to the static imports) here.