使用静态导入的继承静态方法时,我遇到了一些奇怪的行为:
COM /示例/ UTIL / BaseUtil.java:
package com.example.util;
/*default*/ class BaseUtil {
public static final void foo(){ System.out.println("foo"); }
}
COM /示例/ 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 /示例/ 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();
}
}
运行UtilTest
会导致未经检查的异常!
线程“main”中的异常java.lang.IllegalAccessError:尝试从类com.example.UtilTest访问类com.example.util.BaseUtil
at com.example.UtilTest.main(UtilTest.java:15)
但是,如果我通过Util
引用方法(没有静态导入),一切都按预期工作:
COM /示例/ UtilTest.java
package com.example;
import com.example.util.Util;
public class UtilTest {
public static void main(String[] args) {
Util.bar();
Util.foo();
}
}
那么,是什么给出了?
答案 0 :(得分:5)
/*default*/ class BaseUtil { //only visible within the package com/example/util
该类具有defualt访问说明符,使其从该包外部不可见。
你需要公开它。
<强>更新强>
以下是反编译的样子:
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
}
以下是我使用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();
}
}
当然不会编译。
在这里看起来像编译器中的漏洞(可能是由于静态导入)。
答案 1 :(得分:1)
不完全是答案,但在导入静态函数时还需要考虑其他事项。
当您使用静态函数/常量时,它们有时可以在线编译。这取决于您使用的编译器。我不记得我的头顶是哪一个。
当您从外部库导入静态变量/函数,然后在运行时升级该库时,这是一个问题,您的代码仍将具有OLD静态函数。
我的建议是完全避免使用静态函数,而是使用单例对象。 使用诸如spring之类的框架在运行时将单例注入到类中。
最好将此对象设为final,并使用构造函数进行设置。
这也使得测试变得更容易,因为你可以模拟单例。
答案 2 :(得分:0)
您的代码的第一个版本有效地编译为
package com.example;
public class UtilTest {
public static void main(String[] args) {
com.example.util.Util.bar();
com.example.util.BaseUtil.foo();
}
}
并且由于BaseUtil
具有包范围,因此您无法从其他包中调用它并且会出现异常。
您的代码的第二个版本有效地编译为
package com.example;
public class UtilTest {
public static void main(String[] args) {
com.example.util.Util.bar();
com.example.util.Util.foo();
}
}
由于Util
是公共类,因此您可以访问包括foo
在内的所有方法,因为[{1}}对于Util来说是可见的。
令我困惑的是为什么任何版本都能正确编译?