web-dev-qa-db-ja.com

インターフェイスの静的初期化

次のようなものを書き込もうとしたとき:

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
}

この振る舞いを私に説明してもらえますか?

42
Sergey Morozov

静的な初期化はできますが、静的なブロックはできません。静的初期化が実装するために静的コードブロックを必要とするという事実は、Java構文を変更します。

重要なのは、インターフェイスにコードを置くつもりはない(Java 8)の前)が、フィールドを初期化することは許可されているということです。

ところで、あなたは好きなだけのコードを持つネストされたクラスまたは列挙を持つことができ、フィールドを初期化しながらこれを呼び出すことができます。 ;)

15
Peter Lawrey

インターフェイスには副作用がないようにし、静的初期化子にも適用する必要があります。それらは、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印刷されますか?後でコードを推測して実行してください。答えはあなたを驚かせるかもしれません。

21
Holger

同じファイルに2つ目の非パブリッククラスを配置することで、問題を回避できます。

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は非常に賢い言語です。バカなことをするのは難しくなりますが、不可能ではありません。 :)

6
OldCurmudgeon

インターフェイスには初期化ブロックはありません。次のコードスニペットが役立つ場合があります。

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

}
0
Siddappa Walake