문제

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?

도움이 되었습니까?

해결책

/*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.

다른 팁

Not quite the answer, but something else to consider when importing static functions.

When you are working with static functions/constants, they can sometimes get compiled in-line. This depends on which compiler you are using. I can't remember off the top of my head which ones.

This is a problem when you import the static variable/function from an external library, then upgrade that library at runtime, your code will still have the OLD static function in it.

My suggestion is to avoid static functions altogether, and instead use a singleton object. Use a framework such as spring to inject the singleton into your class at runtime.

It's good practice to make this object final, and use the constructor to set it.

This also makes testing easier as you can mock the singleton.

The first version of your code compiles effectively to

package com.example;

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

and since BaseUtil has package scope you can't call it from a different package and you get an exception.

The second version of your code compiles effectively to

package com.example;

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

Since Util is a public class you get access to all the methods including foo, since foo is visible to Util.

What puzzles me is why any of versions compile correctly?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top