java - When is an interface with a default method initialized? -
while searching through java language specification answer this question, learned that
before class initialized, direct superclass must initialized, but interfaces implemented class not initialized. similarly, superinterfaces of interface not initialized before interface initialized.
for own curiosity, tried and, really, interface interfacetype not initialized.
public class example { public static void main(string[] args) throws exception { interfacetype foo = new interfacetypeimpl(); foo.method(); } } class interfacetypeimpl implements interfacetype { @override public void method() { system.out.println("implemented method"); } } class classinitializer { static { system.out.println("static initializer"); } } interface interfacetype { public static final classinitializer init = new classinitializer(); public void method(); } this program prints
implemented method however, if interface declares default method, initialization occur. consider interfacetype interface given as
interface interfacetype { public static final classinitializer init = new classinitializer(); public default void method() { system.out.println("default method"); } } then same program above print
static initializer implemented method in other words, static field of interface initialized (step 9 in detailed initialization procedure) , static initializer of type being initialized executed. means interface initialized.
i not find in jls indicate should happen. don't me wrong, understand should happen in case implementing class doesn't provide implementation method, if does? condition missing java language specification, did miss something, or interpreting wrongly?
this interesting issue!
it seems jls section 12.4.1 ought cover definitively. however, behavior of oracle jdk , openjdk (javac , hotspot) differs what's specified here. in particular, example 12.4.1-3 section covers interface initialization. example follows:
interface { int = 1, ii = test.out("ii", 2); } interface j extends { int j = test.out("j", 3), jj = test.out("jj", 4); } interface k extends j { int k = test.out("k", 5); } class test { public static void main(string[] args) { system.out.println(j.i); system.out.println(k.j); } static int out(string s, int i) { system.out.println(s + "=" + i); return i; } } its expected output is:
1 j=3 jj=4 3 and indeed expected output. however, if default method added interface i,
interface { int = 1, ii = test.out("ii", 2); default void method() { } // causes initialization! } the output changes to:
1 ii=2 j=3 jj=4 3 which indicates interface i being initialized wasn't before! mere presence of default method enough trigger initialization. default method doesn't have called or overridden or mentioned, nor presence of abstract method trigger initialization.
my speculation hotspot implementation wanted avoid adding class/interface initialization checking critical path of invokevirtual call. prior java 8 , default methods, invokevirtual never end executing code in interface, didn't arise. 1 might think part of class/interface preparation stage (jls 12.3.2) initializes things method tables. perhaps went far , accidentally did full initialization instead.
i've raised question on openjdk compiler-dev mailing list. there's been reply alex buckley (editor of jls) in raises more questions directed @ jvm , lambda implementation teams. notes there's bug in spec here says "t class , static method declared t invoked" should apply if t interface. so, might there both specification , hotspot bugs here.
disclosure: work oracle on openjdk. if people think gives me unfair advantage @ getting bounty attached question, i'm willing flexible it.
Comments
Post a Comment