接口中的静态初始化

Ser*_*zov 44 java interface static-initialization

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

public interface MyInterface {
    static {
        System.out.println("Hello!");
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器无法编译它.

但是当我写这样的东西时:

interface MyInterface {
    Integer iconst = Integer.valueOf(1);
}
Run Code Online (Sandbox Code Playgroud)

并反编译它,我看到静态初始化:

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
}
Run Code Online (Sandbox Code Playgroud)

你能告诉我这个行为吗?

Hol*_*ger 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() {
  }
}
Run Code Online (Sandbox Code Playgroud)

你觉得什么时候interface Foo initialized打印?之后尝试猜测并运行代码.答案可能会让你大吃一惊.

  • @Dolda2000:你不能使编程语言防弹,好吧,至少在没有大幅降低其实用性的情况下.因此,他们只有在设计时才能尝试的事情,就是让正确的事情变得简单,不正确的事情难以实现. (3认同)
  • @Dolda2000:我想,Java并不介意...... (3认同)
  • 我在过去的5年里一直是一名java开发人员,答案让我感到惊讶.多可惜.谢谢! (2认同)
  • @Holger 顺便说一句,惊喜应该从哪里来?接口中的静态字段初始化仅在实际使用时才延迟? (2认同)
  • @Eugene 没有单独的“静态字段初始化”,而是整个类/接口的一个初始化。该字段尚未初始化的事实表明整个接口初始化没有发生(在此问答的上下文中,这意味着假设的“static { ... }”块也不会被执行)因此可能的行为令开发人员惊讶的是,使用实现接口的类,甚至调用其上的接口方法,都不会触发接口初始化(甚至不太直观,“默认”方法会改变这一点)。 (2认同)

Pet*_*rey 16

您可以进行静态初始化,但不能使用静态块.静态初始化需要实现静态代码块的事实确实会改变Java语法.

关键是你不打算在接口中使用代码(在Java 8之前),但是你可以初始化字段.

顺便说一句,你可以有一个嵌套的类或枚举,它有你想要的代码,你可以在初始化字段时调用它.;)

  • @frostjogla接口不应该有副作用. (4认同)
  • @frostjogla接口只用于定义合同,不提供任何实现.允许常量是基于它们可能在方法中使用的基础. (2认同)
  • 有时接口包含公共静态最终常量...如果你有一个Set或Map或者什么,初始化(可读)可能需要一个静态块,而不会引入任何副作用 (2认同)

Old*_*eon 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";
  }
}
Run Code Online (Sandbox Code Playgroud)

用以下方法测试:

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

}
Run Code Online (Sandbox Code Playgroud)

打印:

Test Hello
Static Hello
Hello again
Hello
Run Code Online (Sandbox Code Playgroud)

Java是一种如此聪明的语言 - 它使得很难做出愚蠢的事情,但并非不可能.:)