Assertions in static blocks ?
Ulf Zibis
Ulf.Zibis at gmx.de
Sat Mar 6 12:24:04 PST 2010
David, very much thanks for your detailed explanation and your effort
checking the spec. :-)
I've found a much simpler workaround which seems to work as expected:
class EUC_TWMapping3 extends EUC_TWMapping2 {
static final short PL0_5_B2C_RANGE; // plane 0, 5 b2c range
static final short PLANE_B2C_RANGE; // plane 2..4, 6..15 b2c range
static {
PL0_5_B2C_RANGE = 0x2300; // Initialize here to force the
static block
PLANE_B2C_RANGE = 0x1f00; // and the assertions, if enabled, to
run.
// assert plane offsets and content
for (int p=0, range, offset=0; p<b2c.length; p++) {
range = p % 4 == 0 ? PL0_5_B2C_RANGE : PLANE_B2C_RANGE;
for (int i=range; i<b2c[p].length(); i++)
assert b2c[p].charAt(i) == UNMAPPABLE_DECODING;
assert (offset += range) <= Character.MAX_VALUE + 1;
}
}
}
-Ulf
Am 06.03.2010 20:55, schrieb David Schlosnagle:
> Ulf,
>
> The behavior you're encountering is consistent with JLS §4.12.4 [1] which
> states:
> We call a variable, of primitive type or type String, that is final and
> initialized with a compile-time constant expression (§15.28) a constant
> variable. Whether a variable is a constant variable or not may have
> implications with respect to class initialization (§12.4.1), binary
> compatibility (§13.1, §13.4.9) and definite assignment (§16).
>
> Later in JLS §13.1 [2] it states:
> References to fields that are constant variables (§4.12.4) are resolved at
> compile time to the constant value that is denoted. No reference to such a
> constant field should be present in the code in a binary file (except in
> the class or interface containing the constant field, which will have code
> to initialize it), and such constant fields must always appear to have been
> initialized; the default initial value for the type of such a field must
> never be observed. See §13.4.8 for a discussion.
>
> Check out Java Puzzler 93: Class Warfare [3] which gives an example of this and
> how it impacts binary compatibility. Josh and Neal also covered this in the
> 2009 JavaOne Puzzler talk, see #7 "When Words Collide" [4].
>
> Based on that, anywhere that PL0_5_B2C_RANGE or PLANE_B2C_RANGE are used the
> actual values will be inlined into the referencing class file at compile time
> as "sipush 8960" or "sipush 7936" respectively, and therefore do not reference
> the class EUC_TWMapping3 or cause it to be initialized.
>
> If you do want to ensure the assertions are run when at class initialization,
> I'd recommend something like the following which will ensure that the value is
> not inlined at compile time:
>
> class EUC_TWMapping3 extends EUC_TWMapping {
> static final short PL0_5_B2C_RANGE = planeZeroFiveB2CRange(); //
> plane 0, 5 b2c range
> static final short PLANE_B2C_RANGE = planeB2CRange(); // plane
> 2..4, 6..15 b2c range
>
> private static final short planeZeroFiveB2CRange() {
> short range = 0x2300; // plane 0, 5 b2c range
> assert range>= b2c.length; // assert by values from EUC_TWMapping
> return range;
> }
>
> private static final short planeB2CRange() {
> short range = 0x1f00; // plane 2..4, 6..15 b2c range
> assert range<= b2c.length; // assert by values from EUC_TWMapping
> return range;
> }
> }
>
> [1]: http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.4
> [2]: http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#13.1
> [3]: http://www.javapuzzlers.com
> [4]: http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-5186&yr=2009&track=javase
>
> - Dave
>
>
>
> On Sat, Mar 6, 2010 at 6:35 AM, Ulf Zibis<Ulf.Zibis at gmx.de> wrote:
>
>> Am 06.03.2010 02:28, schrieb Keith McGuigan:
>>
>>> Ulf Zibis wrote:
>>>
>>>> Neal, Keith, thanks for your answer.
>>>>
>>>> ... but shouldn't javac claim, that there the code in the static block
>>>> will be *never reached*, if there is no trigger to run it?
>>>>
>>> Not really. That would be like claiming that the code in a method will
>>> never be reached if no one calls the method. javac can't know that you're
>>> not going to take that class and deploy it somewhere else with other code
>>> that will end up calling the method (or initializing the class, etc.).
>>>
>> But javac can know about the risk, because running Class.forName() is "not
>> very common", especially if there is nothing but constants in that class.
>> The minimum, javac could do is to throw a warning.
>>
>> On the other hand, javac throws errors, even if the stated problem never
>> occurs:
>> char c1 = 12345;
>> char c2 = c1 % 100;
>> would result in ERROR: "possible loss of precision", but
>> c1 *= 12345;
>> compiles without problem.
>>
>> Do you know, if following static initializer will be guaranteed to run, when
>> accessing the static value? :
>>
>> class EUC_TWMapping3 extends EUC_TWMapping {
>> static final short PL0_5_B2C_RANGE; // plane 0, 5 b2c range
>> static final short PLANE_B2C_RANGE; // plane 2..4, 6..15 b2c range
>> static {
>> PL0_5_B2C_RANGE = 0x2300; // initialized here to force the
>> assertions!
>> PLANE_B2C_RANGE = 0x1f00; // " " "
>> // assert by values from EUC_TWMapping
>> assert PL0_5_B2C_RANGE>= b2c.length;
>> assert PLANE_B2C_RANGE<= b2c.length;
>> }
>> }
>>
>> -Ulf
>>
>>
>>
>>
>>
>
>
More information about the compiler-dev
mailing list