There is a difference between what is required at the Java language level and what is required at the bytecode level, which is much weaker.
At the Java language level, you should have a constructor call as the first statement, but the compiler will insert it implicitly if you leave it alone.
At the bytecode level, the only requirement is that there is exactly one constructor call along each returned code, plus there are restrictions on what you can do with the this value before initialization.
In particular, this means that
- A constructor call should not appear at the beginning of a method
- You can choose between calls to different constructors based on conditional logic
- There may be exception handlers in the constructor, including catch exceptions thrown by the superclass constructor
- You cannot have any constructor calls at all if each code path throws an exception or goes into an infinite loop.
The first option actually appears in Javac-generated code, because in Java you can pass an expression as an argument to invoke the constructor, and the code to evaluate this expression must obviously happen before the constructor is invoked. But the rest of these options cannot be executed in Java.
Note that if you violate these restrictions, what happens if you remove the constructor call from the regular Java constructor that returns normally, the constructor will now be invalid because it will return, but does not have a ctor call. Thus, an attempt to load a class will work at runtime using VerifyError.
For completeness, here is what you can do with the uninitialized value of this : compare it to zero and save (but not read) the fields defined in the same class.
Not so much, right? But the ability to store fields defined in one class before calling ctor is actually used by the Java compiler. At the bytecode level, there is no concept of inner classes, so when you refer to an outer class in an inner class, the compiler generates a hidden field in the inner class containing a reference to the outer class. To ensure that this works correctly, if the superclass constructor calls a method that is redefined in the inner class and calls the outer class, this hidden field must be initialized before the superclass constructor is called. Of course, you can do this when writing bytecode itself.