The puzzling part to me, however, is this:
Example 2: A simple name that refers to a final variable whose initializer is a constant expression is a constant expression.
Since the static method initializes uninitialized static variables BEFORE the class constructor, I would have (falsely) thought that it is interpreted at compile time. That's why I thought it would have worked, whereas it actually failed.
The part that confuses me is that if you do the serialVer method I describe, where it uses the static {} method to set the serialVer from a class containing constants, you'll notice that the class has already been stamped with the constant value (in another class that is assigned through the static {} method) once the class is compiled. This leads me to believe that static {} runs at compile time---or perhaps this is a special case?
Unfortunately, I have my code sample (a set of classes) on my machine at work so I cannot post it here. I will describe it, but if someone needs to see an example, I can post the code.
I know this is straying a bit from the original question, but I consider it to be interrelated (because the static initialization on the public final static (const) is then related to "case" due to the final. Yeah, yeah....odd, strange, but definitely interesting!!
Anyway, what I did was I created a serializable class, say AClass, another serializable class, say BClass, and declared a reference in AClass to BClass as well as a reference in AClass to an array of BClass. I also threw in a few variables including a transient for good measure.
Next, I compiled them and did a serialVer (just like java or javac) at the command line to get the serialVer. I then created a third class (a static one) where I defined constants for each serialVer value. Next, in the original two classes, I defined "public static final int serialVer;" (this is from memory so I apologize if I have the int part wrong...might be a long, but I think it is an int). Finally, in each of the two classes, I created a method as such:
Again, this is a similar example, but is basically what I did.
Next, I added a new instance variable to AClass and deleted an existing instance variable from AClass. Those are within the rules of allowable changes...the result is that when the object is deserialized, the new variable has its default value (depends on the data type) and the deleted one is simply not used.
However, if I hadn't defined serialVer in each serializable class, these changes would have caused AClass' "stamp" to be different (it would have a different serialVer) and a deserialization would throw an Exception. This is much like casting...basically, you're saying "I know what I'm doing." and it takes your
word for it.
However, if you run serialVer (at the cmd prompt) on these compiled classes, you'll get whatever value you defined in your constants...that indicates to me that it is evaluated/assigned AT COMPILE TIME...not at RUN TIME. But if that is the case, then the static initialization on that final variable should have worked in the case statement (which brings us back to the initial point). Yet, it doesn't work, as it thinks the final var has not been initialized.
So how is this paradox explained? I realize this will probably not be on the exam in this form, but nevertheless, it certainly aids in deep understanding of several inter-related concepts.
Ross