接口中的静态初始化

时间:2013-11-01 07:56:44

标签: java interface static-initialization

当我尝试写这样的东西时:

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
}

请你解释一下这种行为吗?

5 个答案:

答案 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中不能定义版本,因为它是一个接口。根据定义,它没有代码。