Name: boT120536 Date: 03/09/2001
java version "1.3.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0_01)
Java HotSpot(TM) Client VM (build 1.3.0_01, mixed mode)
The virtual machine initializes a class in violation of JLS2 12.4.1 and JVMS2
5.4.3, 5.5, and 6. Referencing a class via invokestatic, getstatic, or
putstatic, should only initialize the class if that class also declares the
static member being referenced.
First, compile these three source files:
class A {
static void foo() {
System.out.println("A");
}
static {
System.out.println("Init. A");
}
}
class B extends A {
static void foo() {
System.out.println("B");
}
static {
System.out.println("Init. B");
}
}
class Test {
public static void main(String[] args) {
B.foo();
}
}
Note that Test.class now includes the bytecode invokestatic B.foo(). Now,
comment out the declaration of foo inside B, and recompile just B.java, so that
the call in Test.main to B.foo() will end up invoking the inherited A.foo():
class B extends A {
static {
System.out.println("Init. B");
}
}
Now, when executing these files, the output is:
$ ls -l *.class
-rw-r--r-- 1 eblake fpga 442 Mar 9 14:50 A.class
-rw-r--r-- 1 eblake fpga 367 Mar 9 15:13 B.class
-rw-r--r-- 1 eblake fpga 482 Mar 9 15:11 Hello.class
$ java Hello
Init. A
Init. B
A
This means that the virtual machine, when resolving the invokestatic B.foo()
call, initialized class B (which of course initializes the superclass A first).
However, quoting JVMS 6 on invokestatic bytecode:
"On successful resolution of the method, the class that declared the resolved
field is initialized (?5.5) if that class has not already been initialized."
Likewise, in JLS 12.4.1, a class T is initialized if "T is a class and a static
method declared by T is invoked," and B does not declare foo(). Therefore, B
should not be initialized, and the correct output should be:
Init. A
A
(Note that a clean compilation of all three files, using the second version of
B, will give the correct output, but that this is due to a bug in javac.
According to JLS 15.12.1, 13.1, and 13.4.11, the bytecode emitted in Test.class
should refer to B.foo() whether B declares or inherits foo, but javac currently
emits a reference to A.foo() when B does not declare foo.)
(Review ID: 118533)
======================================================================
- duplicates
-
JDK-4424105 Java initializes classes it shouldn't when compiled with -target 1.2
- Closed