static initialization in interface

24,310

Solution 1

You can have static initialisation, but you cannot have a static block. The fact the static initialisation needs a static code block to implement does change the Java syntax.

The point is you are not meant to have code in an interface (before Java 8) but you are allowed to initialise fields.

BTW you can have a nested class or enum which has as much code as you like and you can call this while initialising a field. ;)

Solution 2

Interfaces should not have side-effects and that even applies to static intializers. They would have highly JVM-implementation dependent behavior. Look at the following code

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() {
  }
}

What do you think, when will interface Foo initialized be printed? Try to guess and run code afterwards. The answer might surprise you.

Solution 3

You can get around the problem - if you see it as a problem - by putting a second non-public class in the same file.

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

Testing this with:

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

}

prints:

Test Hello
Static Hello
Hello again
Hello

Java is such a clever language - it makes it difficult to do stupid things but not impossible. :)

Share:
24,310

Related videos on Youtube

Sergey Morozov
Author by

Sergey Morozov

SOreadytohelp

Updated on July 09, 2022

Comments

  • Sergey Morozov
    Sergey Morozov almost 2 years

    When I tried to write something like this:

    public interface MyInterface {
        static {
            System.out.println("Hello!");
        }
    }
    

    the compiler could not compile it.

    But when I wrote something like this:

    interface MyInterface {
        Integer iconst = Integer.valueOf(1);
    }
    

    and decompiled it, I saw static initialization:

    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
    }
    

    Could you please explain this behavior to me?

  • Sergey Morozov
    Sergey Morozov over 10 years
    Thanks for answer. Maybe you know why that did(disable static block in interface)?
  • Holger
    Holger over 10 years
    The entire answer is missing the point of the question. It’s not about static methods, it’s about static initializers.
  • Holger
    Holger over 10 years
    @frostjogla interfaces should not have side-effects.
  • Vishy
    Vishy over 10 years
    @frostjogla interfaces are only there to define a contract, not provide any implementation. Constants are allowed on the basis they might be used in a method.
  • hsestupin
    hsestupin about 8 years
    I'm working as a java developer for the last 5 years and the answer truly surprised me. What a shame. Thanks!
  • Kip
    Kip almost 8 years
    Sometimes interfaces contain public static final constants... if you have a Set or Map or something, the initialization (to be readable) might require a static block, without introducing any side effects
  • Dolda2000
    Dolda2000 over 7 years
    That being said, though, the side effects can just as well be brought about via functions called by initializer expressions, just as you demonstrated. Forbidding static {} blocks does nothing to prevent that.
  • Holger
    Holger over 7 years
    @Dolda2000: you can’t make a programming language bullet-proof, well, at least not without dramatically reducing its usefulness. So they only thing you can try when designing, is to make correct things easy and incorrect things harder to achieve.
  • Dolda2000
    Dolda2000 over 7 years
    @Holger: Perhaps, but in this case, it also creates hassles when one wants to initialize static fields in a more complex way than simple expressions allow. Not too seldom I find myself having to create useless classes containing private static methods just for initializing some field that requires a for loop or something. Makes one hold a grudge.
  • Holger
    Holger over 7 years
    @Dolda2000: maybe you’re overusing static fields in interfaces…
  • Dolda2000
    Dolda2000 over 7 years
    @Holger: Or maybe the language is just being too opinionated. Anyway, I take my simple revenge by naming the useless classes things such as JavaIsStupid, so it's alright; it's a situation of mutual abuse. :)
  • Sergey Morozov
    Sergey Morozov over 6 years
    Your example may confusing people because your second code snippet shows class MyInterface declaration not an interface.
  • Siddappa Walake
    Siddappa Walake over 6 years
    @Sergey, Thank you for alerting me up. That should be a class and I changed it.
  • Eugene
    Eugene about 6 years
    @Holger where should the surprise come from btw? that the static field initialization in interface is deferred only when actually used?
  • Holger
    Holger about 6 years
    @Eugene there is no individual “static field initialization”, but only one initialization for the entire class/interface. The fact that the field has not been initialized indicates that the entire interface initialization did not happen (in the context of this Q&A, this implies that hypothetical static { … } blocks would not have been executed as well) So the behavior that may surprise developers is that neither, using a class implementing the interface nor even invoking an interface method on it, will trigger the interface initialization (even less intuitive, default methods change that).