48

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

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
}

你能向我解释一下这种行为吗?

4

5 回答 5

26

接口不应该有副作用,甚至适用于静态初始化器。它们将具有高度依赖于 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印刷?之后尝试猜测并运行代码。答案可能会让你大吃一惊。

于 2013-11-01T08:54:09.800 回答
23

您可以进行静态初始化,但不能拥有静态块。静态初始化需要一个静态代码块来实现这一事实确实改变了 Java 语法。

关键是您不应该在接口中包含代码(在 Java 8 之前),但您可以初始化字段。

顺便说一句,您可以拥有一个嵌套类或枚举,其中包含尽可能多的代码,您可以在初始化字段时调用它。;)

于 2013-11-01T08:07:24.397 回答
9

您可以通过在同一个文件中放置第二个非公共类来解决问题 - 如果您认为这是一个问题。

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 是一种非常聪明的语言——它使做愚蠢的事情变得困难,但并非不可能。:)

于 2013-11-01T09:38:30.970 回答
0

接口没有任何初始化块。以下代码片段可能会有所帮助..

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;
   }

}
于 2017-11-16T10:36:48.403 回答
-2

在接口中声明静态方法是没有意义的。它们不能通过正常调用 MyInterface.staticMethod() 来执行。(编辑:由于最后一句话让一些人感到困惑,调用 MyClass.staticMethod() 精确地执行了 MyClass 上的 staticMethod 的实现,如果 MyClass 是一个接口则不存在!)如果你通过指定实现类来调用它们 MyImplementor.staticMethod()那么你必须知道实际的类,所以接口是否包含它是无关紧要的。

更重要的是,静态方法永远不会被覆盖,如果你尝试这样做:

MyInterface var = new MyImplementingClass();
var.staticMethod();

static 的规则说必须执行在声明的 var 类型中定义的方法。因为这是一个接口,所以这是不可能的。

当然,您始终可以从方法中删除 static 关键字。一切都会好起来的。如果从实例方法调用它,您可能必须禁止显示一些警告。

要回答下面的一些评论,您无法执行“result=MyInterface.staticMethod()”的原因是它必须执行 MyInterface 中定义的方法版本。但是在 MyInterface 中不能定义一个版本,因为它是一个接口。它没有定义的代码。

于 2013-11-01T08:39:01.383 回答