| benf.org : other : cfr : How are Field Initialisers compiled? |
Other than in the case of a static primitive (String counts as a primitive here!) initialiser, there's no difference between initialising a field in every constructor, vs at point of declaration
Links from the 'class file format' doc:
Q: What's the difference between
// case 0
public class MemberTest {
private final Map<String, String> m = new HashMap<String, String>();
public MemberTest2() {
}
}
and
// case 1
public class MemberTest {
private final Map<String, String> m;
public MemberTest2() {
this.m = new HashMap<String, String>();
}
}
A: ... absolutely nothing. (or certainly not with the compiler I have now ;) ) - these two compile to the same bytecode - which is that of case 1.
If you decompile these two with cfr_0_13 with the argument '--liftconstructorinit false' you will see the latter code in both case.
Any non-static, non-primitive field initialiser is copied into EVERY constructor, after the possible super(..) call.
The only (fairly obvious exception to this is chained constructors - in which case the chainer (the constructor which calls this(...) does NOT get a copy of the initialisation code.
// case 2
public class MemberTest {
private int x = 3;
public MemberTest2() {
}
}
vs
// case 3
public class MemberTest {
private int x;
public MemberTest2() {
this.x = 3;
}
}
Again, these two compile to the same bytecode.
// case 4
public class MemberTest {
private final int x = 3;
public MemberTest2() {
}
}
vs
// case 5
public class MemberTest {
private final int x;
public MemberTest2() {
this.x = 3;
}
}
These two produce different bytecode - (finally!) - in case 4, the compiler makes use of the ConstantValue attribute in a field_info structure - See 'Java Class file format - 4.7.2 The ConstantValue Attribute'
/*
* Decompiled with CFR.
*/
public class MemberTest {
private final int x = 3; // (comes from constant value attribute)
public MemberTest() {
this.x = 3; // (comes from bytecode)
}
}
Hang on! - this has defined a ConstantValue attribute, AND it has bytecode based initialisation! The relevant information is this para from the Class file spec:
"... if a field_info structure representing a non-static field has a ConstantValue attribute, then that attribute must silently be ignored. Every Java virtual machine implementation must recognize ConstantValue attributes."
... for some reason, the compiler has emitted a constantValue attribute, but has had to emit bytecode as well. The only place ConstantValue attributes can have meaning is in static initialisers.
// case 6
public class MemberTest {
private static final int x = 3;
}
vs
// case 7
public class MemberTest {
private static final int x;
static {
MemberTest.x = 3;
}
}
These do produce different initialisations - the former uses the ConstantValue attribute, the latter the bytecode.
| Last updated 05/2013 |