Class Literals and Class Initialization (Jikes Example)
I was just over at the Jikes website for the first time trying to find out
what theyre all about and got reeled into reading their FAQ, lol.
Their statement, "The FAQ describes some of the side effects of this strict language conformance" piqued my interest.
http://jikes.sourceforge.net/faq/user-index.shtml#compatible
In one of the FAQ examples they say:
"The Java Language Specification does not allow class literals to cause class initialization, even though javac has always done it this way."
Because of this, the following code wrongly outputs 2 (I checked with
J6 and it does):
class Super{
staticint i = 1;
staticvoid m(Class c){
System.out.println(i);
}
publicstaticvoid main(String[] args){
m(Sub.class);
}
}
class Subextends Super{
static{ i = 2;}
}
I am VERY confused. I dont understand the
intent of the programmer who would write that code.
Can anyone please help me out?
The "fix" they suggest is equally over my head:
staticvoid m(Class c){
// we aren't sure if c is initialized, hence this try-block
try{
if (c !=null)
c.forName(c.getName());
}catch (Exception e){
// shouldn't get here, and even if we do, we ignore it
}
System.out.println(i);
}
It's just code to demonstrate some of the more obscure semantic details of the JVM, although I'm not convinced that it demonstrates what it says it's demonstrating. I don't see why this would prove that initialization is happening at the class literal and not, say, when m() is invoked.
You normally wouldn't write code like that.You might occasionally, but generally you should be avoiding static stuff anyway.
The fix is a way to write code that wouldn't depend on one particular way of dealing with a supposed divergence between the specification and a common implementation, so that the same code could run on different implementations of the JVM, whether it followed the spec or followed the common divergence from the spec.
How does the call to m(...) know whether to call Super or Sub?
I guess im confused because I dont see how just typing or
instantiating an instance of Sub is at all related to the call to m(...)?
Its as if just because you create a Sub object that decides what
m(...) is going to call.
This is unnecessary voodoo.
[hit post twice because of lag]Message was edited by: TuringPest
> How does the call to m(...) know whether to call
> Super or Sub?
>
It calls Super's m() because
1) Static methods are not overridden
and
2) Sub has no m() of its own.
> I guess im confused because I dont see how just
> typing or
> instantiating an instance of Sub is at all related to
> the call to m(...)?
There is no instance of Sub. It's about class initialization (e.g., running static initializers), not about instantiation.
> Its as if just because you create a Sub object that
> decides what
> m(...) is going to call.
No Sub object or Super object is being created. There's only one m() method, and we're telling it what its parameter is.
> How does the call to m(...) know whether to call
> Super or Sub?
I'm assuming you are asking whether the call to m() in both of the examples posted calls the m() method from the Super class or the m() method from the Sub class. If that's the case, then obviously since it's a static method of the Super class, the code calls the method from the Super class.
> How does the call to m(...) know whether to call
> Super or Sub?
Eh? m() is defined in the superclass and inherited by the subclass.m() doesn't really call either class, although one class is passed as a parameter.
> I guess im confused because I dont see how just typing or
> instantiating an instance of Sub is at all related to
> the call to m(...)?
I think that's their point. I think what they're trying to say is that if Sub.class is merely named as a class literal, it's not supposed (as per the spec) to cause class initialization, and therefore the static block in Sub shouldn't be invoked, and therefore i should be 1 when m prints it out. But I'd be curious whether passing the literal as a parameter might be what causes class initialization. I'd think that a better test might be:
Sub.class;
m();
if m were changed to take no arguments. But since I haven't checked the spec lately to confirm this, I'm not sticking by it either.
> Its as if just because you create a Sub object that
> decides what
> m(...) is going to call.
But it doesn't call anything really.
> This is unnecessary voodoo.
It's not really supposed to be elegant production code; it's supposed to demonstrate an obscure (mis)implementation, a bug.
> I was just over at the Jikes website for the first> time trying to find out> what theyre all about ...One thing you might want to note about them, is that the compiler is 1.4 compatible only.
BTW, I just ran the test, and it output 1.(jdk 1.5, Windows)Message was edited by: paulcw
I get 2 from java version "1.4.2_12"Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_12-270)Java HotSpot(TM) Client VM (build 1.4.2-70, mixed mode)onDarwin Kernel Version 7.9.0
D'oh! Dont mind me. I am SO sorry, lol.
For some reason the Class argument being passed in the m(...)
method just totally scrambled my brain up and I couldnt see the
code right.
If Sub is initialized its static initializer changes "i" in the class
Super resulting in an ouput of 2.
So their argument is whether the spec dictates that "Sub.class" be
sufficient to force initializing Sub or whether "forcing
class initialization" (their words) requires code such as "Class.forName".
Thanks for your replies.
>> BTW, I just ran the test, and it output 1.
Thats strange. Why would 1.4 be 2 (as someone else sad), 1.5 = 1,
and 1.6 = 2?
Ah-ha...
I forgot that I had my IDE options set to "-source 1.4 -target 1.4".
With normal J6 compilation it is indeed 1.
Its interesting that those flags will even unfix those types of
issues, lol.
> Its interesting that those flags will even unfix> those types of > issues, lol.Bug-for-bug compatibility, baby!:-)
> Bug-for-bug compatibility, baby!You need to trademark that!
> > Bug-for-bug compatibility, baby!> > You need to trademark that!I'm far from the first to utter that phrase.
> > > Bug-for-bug compatibility, baby!> > > > You need to trademark that!> > I'm far from the first to utter that phrase.I think Microsoft has even patented it.
> > > > Bug-for-bug compatibility, baby!
> > >
> > > You need to trademark that!
> >
> > I'm far from the first to utter that phrase.
>
> I think Microsoft has even patented it.
Wouldn't surprise me. :-)
[url http://www.theonion.com/content/node/29130]Microsoft Patents Ones, Zeroes[/url]
jverda at 2007-7-21 21:07:30 >

Funny: someone just posted this link in another, unrelated thread, and there it is, number five on the list.
http://java.sun.com/j2se/1.5.0/compatibility.html#incompatibilities
I've seen code where the author listed a bunch of class literals in an initialization method, to force the classes to be loaded up front and avoid pauses later on. I always found that annoying; it's nice to learn that I had good reason to. ^_^