当我尝试写这样的东西时:
public interface MyInterface {
static {
System.out.println("Hello!");
}
}
编译器无法编译它。
但是当我写这样的东西时:
interface MyInterface {
Integer iconst = Integer.valueOf(1);
}
并反编译它,我看到了静态初始化:
public interface MyInterface{
public static final java.lang.Integer i;
static {};
Code:
0: iconst_1
1: invokestatic #1; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: putstatic #2; //Field i:Ljava/lang/Integer;
7: return
}
请你解释一下这种行为吗?
答案 0 :(得分:21)
接口不应该有副作用,甚至应用于静态初始化器。它们将具有高度JVM实现依赖性行为。请查看以下代码
public class InterfaceSideEffects {
public static void main(String[] args) {
System.out.println("InterfaceSideEffects.main()");
Impl i=new Impl();
System.out.println("Impl initialized");
i.bla();
System.out.println("Impl instance method invoked");
Foo f=new Impl();
System.out.println("Impl initialized and assigned to Foo");
f.bla();
System.out.println("Foo interface method invoked");
}
}
interface Foo {
int dummy=Bar.haveSideEffect();
void bla();
}
class Bar {
static int haveSideEffect() {
System.out.println("interface Foo initialized");
return 0;
}
}
class Impl implements Foo {
public void bla() {
}
}
您认为什么时候会interface Foo initialized
打印出来?之后尝试猜测并运行代码。答案可能让你感到惊讶。
答案 1 :(得分:14)
您可以进行静态初始化,但不能使用静态块。静态初始化需要实现静态代码块的事实确实会改变Java语法。
关键是你不打算在接口中使用代码(在Java 8之前)但是你可以初始化字段。
顺便说一句,你可以拥有一个嵌套的类或枚举,它有你喜欢的代码,你可以在初始化字段时调用它。 ;)
答案 2 :(得分:6)
你可以通过在同一个文件中放入第二个非公开类来解决问题 - 如果你认为这是一个问题。
public interface ITest {
public static final String hello = Hello.hello();
}
// You can have non-public classes in the same file.
class Hello {
static {
System.out.println("Static Hello");
}
public static String hello() {
System.out.println("Hello again");
return "Hello";
}
}
用以下方法测试:
public class Test {
public void test() {
System.out.println("Test Hello");
System.out.println(ITest.hello);
}
public static void main(String args[]) {
try {
new Test().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
打印:
Test Hello
Static Hello
Hello again
Hello
Java是一种如此聪明的语言 - 它使得很难做出愚蠢的事情,但并非不可能。 :)
答案 3 :(得分:0)
Intefaces没有任何初始化块。以下代码段可能会有所帮助..
public interface MyInterface {
public static final int a;// Compilation error as there is no way for
// explicit initialization
}
public class MyClass {
public static final int a;// Still no error as there is another way to
//initialize variable even though they are final.
static{
a=10;
}
}
答案 4 :(得分:-1)
在接口中声明静态方法永远不会有意义。它们不能通过正常调用MyInterface.staticMethod()执行。 (编辑:因为最后一句话让一些人感到困惑,调用MyClass.staticMethod()会在MyClass上执行staticMethod,如果MyClass是一个接口就不能存在!)如果通过指定实现类MyImplementor.staticMethod()来调用它们那么你必须知道实际的类,所以接口是否包含它是无关紧要的。
更重要的是,静态方法永远不会被覆盖,如果你尝试这样做:
MyInterface var = new MyImplementingClass();
var.staticMethod();
static的规则说必须执行在声明的var类型中定义的方法。由于这是一个界面,这是不可能的。
您当然可以始终从方法中删除static关键字。一切都会好起来的。如果从实例方法调用它,则可能必须禁止某些警告。
要回答下面的一些注释,您无法执行“result = MyInterface.staticMethod()”的原因是它必须执行MyInterface中定义的方法版本。但MyInterface中不能定义版本,因为它是一个接口。根据定义,它没有代码。