Java requires that if you call this() or super() in a constructor, it must be the first statement. Why?
For example:
public class MyClass {
public MyClass(int x) {}
}
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
int c = a + b;
super(c); // COMPILE ERROR
}
}
The Sun compiler says "call to super must be first statement in constructor". The Eclipse compiler says "Constructor call must be the first statement in a constructor".
However, you can get around this by re-arranging the code a little bit:
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
super(a + b); // OK
}
}
Here is another example:
public class MyClass {
public MyClass(List list) {}
}
public class MySubClassA extends MyClass {
public MySubClassA(Object item) {
// Create a list that contains the item, and pass the list to super
List list = new ArrayList();
list.add(item);
super(list); // COMPILE ERROR
}
}
public class MySubClassB extends MyClass {
public MySubClassB(Object item) {
// Create a list that contains the item, and pass the list to super
super(Arrays.asList(new Object[] { item })); // OK
}
}
So, it is not stopping you from executing logic before the call to super. It is just stopping you from executing logic that you can't fit into a single expression.
There are similar rules for calling this()
. The compiler says "call to this must be first statement in constructor".
Why does the compiler have these restrictions? Can you give a code example where, if the compiler did not have this restriction, something bad would happen?
I've found a way around this by chaining constructors and static methods. What I wanted to do looked something like this:
So basically construct an object based on constructor parameters, store the object in a member, and also pass the result of a method on that object into super's constructor. Making the member final was also reasonably important as the nature of the class is that it's immutable. Note that as it happens, constructing Bar actually takes a few intermediate objects, so it's not reducible to a one-liner in my actual use case.
I ended up making it work something like this:
Legal code, and it accomplishes the task of executing multiple statements before calling the super constructor.
You can use anonymous initializer blocks to initialize fields in the child before calling it's constructor. This example will demonstrate :
This will output :
See the example if we are calling the constructor
C(int x)
then value of z is depend on y if we do not callC()
in the first line then it will be the problem for z. z would not be able to get correct value.An exception during construction almost always indicates that the object being constructed could not be properly initialized, now is in a bad state, unusable, and must be garbage collected. However, a constructor of a subclass has got the ability to ignore an exception occurred in one of its superclasses and to return a partially initialized object. In the above example, if the argument given to
new Bad()
is either 0 or greater than 100, then neitheressential1
noressential2
are properly initialized.You may say that ignoring exceptions is always a bad idea. OK, here's another example:
Funny, isn't it? How many objects are we creating in this example? One? Two? Or maybe nothing...
Allowing to call
super()
orthis()
in the middle of a constructor would open a Pandora's box of heinous constructors.On the other hand, I understand a frequent need to include some static part before a call to
super()
orthis()
. This might be any code not relying onthis
reference (which, in fact, already exists at the very beginning of a constructor, but cannot be used orderly untilsuper()
orthis()
returns) and needed to make such call. In addition, like in any method, there's a chance that some local variables created before the call tosuper()
orthis()
will be needed after it.In such cases, you have the following opportunities:
super()
and pre-this()
code. It may be done by imposing a restriction on wheresuper()
orthis()
may occur in a constructor. Actually, even today's compiler is able to distinguish good and bad (or potentially bad) cases with the degree enough to securely allow static code addition at the beginning of a constructor. Indeed, assume thatsuper()
andthis()
returnthis
reference and, in turn, your constructor hasat the end. As well as the compiler rejects the code
with the error "variable x might not have been initialized", it could do so on
this
variable, making its checks on it just like on any other local variable. The only difference isthis
cannot be assigned by any means other thansuper()
orthis()
call (and, as usual, if there is no such call at a constructor,super()
is implicitly inserted by compiler in the beginning) and might not be assigned twice. In case of any doubt (like in the firstget()
, wherex
is actually always assigned), the compiler could return an error. That would be better than simply return error on any constructor where there is something except a comment beforesuper()
orthis()
.Actually,
super()
is the first statement of a constructor because to make sure its superclass is fully-formed before the subclass being constructed. Even if you don't havesuper()
in your first statement, the compiler will add it for you!I found a woraround.
This won't compile :
This works :