This question already has answers here:
Why do this() and super() have to be the first statement in a constructor?
(22 answers)
Closed 6 years ago.
Why Java compiler (javac) sometimes is stupid, sure i know that Java compiler is just a program, but sometimes is designed as stupid (sometimes not), also i'm a fan of Java :)
class Child extends Base {
Child() {
int i = 5; // any statement here.
super(i);
}
}
class Base{
Base(int i) {
}
}
here compiler, claims that the first statements should be a call to the constructor of the inherited class, but if we wrap this first statement inside a static method, it works fine!!!!!!
class Child extends Base {
Child() {
super(foo()); // works fine!!!!
}
static int foo(){
return 5;
}
}
This works fine!!!!!!!, another killer example :
Child() {
try{
super(5);
}catch(Exception e){}
}
try catch is language feature!!!
i know that the compiler oblige us to call the super type constructor, because it should initialise the inherited object before the self object (Generaly Java inheritence is released by object chaining), but i think the compiler should be a little smart, it should let us manipulate the code while we're not touching the object before calling its super constructor, so that MUST work :
Child() {
int i = 5; // this MUST BE acceptable since we didn't touch
// any current object or inherited field or we didn't
// call any method on it.
super(i);
}
but this shouldn't work :
class Child extends Base {
private int i;
Child() {
i = 6; // this shouldn't work (its clear why).
super();
}
}
I just wanted to understand why this is not implemented especially when i see Java can catch unreachable code (a smart feature)???, so for more than 20 years, Java doesn't provide such a BASIC feature, because usually this one sometimes makes code more ugly, sometimes we have to make stupid static methods to avoid this, other time, we just call the super constructor (for javac shut up) then we reinitialize the inherited fields!!!!!!!!
Althought, i don't think, this is a problem of the JVM and bytecode, i think this is can acheive only in javac :)
I really love Java, but this one makes me so angry, i forget to suggest this for the next release (Java 9), i hope it will be included in Java 10, we wait 3 years more, better than not having it at all :'(
I think this may be primarily opinion based.
The way I see it, keeping things simple is sometimes the smarter way to design.
To have the compiler accept some code that the compiler currently doesn't accept, that would (at a minimum) require more complexity. The compiler would have the additional burden of determining which constructs could be allowed, and which constructs wouldn't. The compiler is plenty complex enough. Why add more unnecessary complexity. Especially if the additional complexity doesn't solve, or help us solve, a particular problem.
A requirement that the constructor in the superclass runs before any code in the constructor of the subclass keeps things simpler.
Declaring a static method, as shown in an OP example, doesn't violate the rule about running the constructor in the superclass. A static method is never instantiated. It's part of the class definition, it's not part of an instance of a class.
I think making the compiler smarter (to handle Java code proposed by OP) would not be a smart decision at all.
Q: What real problem does the proposed change to the compiler solve?
Q: And what problems would it potentially create?
Sometimes the choice to avoid additional complexity (and potentially creating more problems) is the smarter choice.
Both answers are totally correct. I am afraid the OP wants to know the reason behind this behavior.
each object does have a constructor
each object inherits from Object - so everything is having a parent object
at each constructor, the inherited parent is called - implicitly (if you don't call super) or explicitly - if you do call super
before you can do anything with your object, it has to be ensured that the inherited object is getting properly initialized.
This is the reason why call to super() has to be the very first in your constructor, and you can not do any operations before calling super().
int i = 5;
does not work, since you could craft a more tricky initialization:
int i=someMethodCall();
which clearly might use any non-initialized inherited field if it would be allowed.
static int foo(){
return 5;
}
works, since it is a static method - which does not depend on the fields of the object instance (and can not see the fields either) - so you can call this before super();
Child() {
try{
super(5);
}catch(Exception e){}
}
does not work, since it is not guaranteed that super() will be called any more. Try..catch would allow super(5) to throw an exception (and not initialize inherited fields), while catching and ignoring this exception would yield a Child object which inherited fields are not initialized at all.
Although the behavior might sound stupid - actually it totally makes sense, no?
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
From the Java specs, here.
They are actively enforcing this.
Here are the parse rules:
ConstructorBody:
{ [ExplicitConstructorInvocation] [BlockStatements] }
ExplicitConstructorInvocation:
[TypeArguments] this ( [ArgumentList] ) ;
[TypeArguments] super ( [ArgumentList] ) ;
ExpressionName . [TypeArguments] super ( [ArgumentList] ) ;
Primary . [TypeArguments] super ( [ArgumentList] ) ;
TypeArguments:
< TypeArgumentList >
ArgumentList:
Expression {, Expression}
Maybe this will give a bit of an insight. Regardless of what you do, the constructor of the super class will always be invoked first.
class Parent {
Parent(int x) {
System.out.println("Parent");
}
}
class Child extends Parent {
Child () {
super(foo());
System.out.println("Child");
}
public static void main(String[] args) {
Child a = new Child(); // prints Parent\nChild
Parent b = new Child(); // prints Parent\nChild
}
static int foo() {
return 5;
}
}
As you can see, regardless of what you do, the Parent constructor is always getting called first. This ensures that if you call any methods on the Parent class in your constructor, the Parent class has already been set up correctly. The fact that this property is strictly enforced is shown by the compiler error if I try to move the System.out.println("Child") line before the call to super().
From [JLS 8.8.7.1],
Let C be the class being instantiated, and let S be the direct
superclass of C.
It is a compile-time error if S is not accessible (§6.6).
If a superclass constructor invocation statement is qualified, then:
If S is not an inner class, or if the declaration of S occurs in a static context, then a compile-time error occurs.
Otherwise, let p be the Primary expression immediately preceding ".super". Let O be the innermost lexically enclosing class of S.
It is a compile-time error if the type of p is not O or a subclass of O, or if the type of p is not accessible (§6.6).
If a superclass constructor invocation statement is unqualified, and
if S is an inner member class, then it is a compile-time error if S is
not a member of a lexically enclosing class of C by declaration or
inheritance.
Related
This question already has answers here:
Why is it that we cannot override static and final methods? [duplicate]
(5 answers)
Closed 1 year ago.
In Java, what is the actual reason behind the inability to write a method in a sub class which has the same name as a final method in the super class? (Please note that I am not trying to override the method, this is why I have put the keyword final.)
Please see the example below:
class A {
public final void method() {
System.out.println("in method A");
}
}
class B extends A {
public void method() {
System.out.println("in method B");
}
}
The problem is expressed as "'method()' cannot override 'method()' in 'A'; overridden method is final" in the IDE; however, I would like to understand what it is about this situation that leads the compiler to fail.
Because in java, overriding isn't optional.
Names of methods at the class level.
At the class level (as in, what is in a class file, and what a JVM executes), method names include their return type and their parameter types (and, of course, the name). At the JVM level, varargs doesn't exist (it's an array instead), generics do not exist (they are erased for the purposes of signature), and the throws clause isn't a part of the story. But other than that, this method:
public void foo(String foo, int bar, boolean[] baz, long... args) throws Exception {}
turns into this name at the class file level:
foo(Ljava/lang/String;I[Z[J)V
which seems like gobbledygook, but [ is 'array of', the primitives get one letter each (Z for boolean, J for longs, I for integer), V is for void, and L is for: Object type. Now it makes sense.
That really is the method name at the class level, effectively (well, we call this its signature). ANY invocation of a method in java, at the class level, always uses the complete signature. This means javac simply cannot compile a method call unless it actually knows the exact method you're invoking, which is why javac doesn't work unless you have the full classpath of everything you're calling available as you compile.
Overriding isn't optional!
At the class level, if you define a method whose full signature matches, exactly, a signature in your parent class, then it is overriding that method. Period. You can't not. #Override as an annotation doesn't affect this in the slightest (That annotation merely causes the compiler to complain if you aren't overriding anything, it's compiler-checked documentation, that's all it is).
javac goes even further
As a language thing, javac will make bridges if you want to tighten the return type. Given:
class Parent {
Object foo() { return null; }
}
class Child extends Parent {
String foo() { return null; }
}
Then at the class level, the full signature of the one method in Parent is foo()Ljava/lang/Object; whereas the one in Child has foo()Ljava/lang/String; and thus these aren't the same method and Child's foo would appear not to be overriding Parent's foo.
But javac intervenes, and DOES make these override. It does this by actually making 2 methods in Child. You can see this in action! Write the above, compile it, and run javap -c -v on Child and you see these. javac makes 2 methods: Both foo()Ljava/lang/String; and foo()Ljava/lang/Object; (which does have the same signature and thus overrides, by definition, Parent's implementation). That second one is implemented as just calling the 'real' foo (the one returning string), and gets the synthetic flag.
Final is what it is
Which finally gets to your problem: Given that final says: I cannot be overridden, then, that's it. You've made 2 mutually exclusive rules now:
Parent's foo cannot be overriden
Child's foo, by definition (because its signatures match), overrides Parent's foo
Javac will just end it there, toss an error in your face, and call it a day. If you imagined some hypothetical javac update where this combination of factors ought to result in javac making a separate method: But, how? At the class level, same signature == same method (it's an override), so what do you propose? That java add a 0 to the end of the name?
If that's the plan, how should javac deal with this:
Parent p = new Child();
p.foo();
Which foo is intended there? foo()Ljava/lang/Object; from Parent, or foo0()L/java/Object; from child?
You can write a spec that gives an answer to this question (presumably, here it's obvious: Parent's foo; had you written Child c = new Child(); c.foo(); then foo0 was intended, but that makes the language quite complicated, and for what purpose?
The java language designers did not think this is a useful exercise and therefore didn't add this complication to the language. I'm pretty sure that was clearly the right call, but your opinion may of course be different.
Final means not just that you can’t override it, it means you can’t work around having that method get called.
When you subclass the object, if you could make a method that shadows that final method, then you could prevent the superclass method from functioning, or substitute some other functionality than what the user of the object would expect. This would allow introducing malicious code and would defeat the purpose of making methods final.
In your case it sounds like making the superclass method final may not have been the best choice.
Is calling super() constructor should be the very first line of the constructor? If so then why? Why can't I do some simple limited calculations before constructor call, for example, constructor parameters calculation?
I found a situation with inner class constructors which can be called with closure specification:
class A {
class Inner1 {
Inner1() {
// do something
}
}
}
class B {
A a1 = new A();
A a2 = new A();
class Inner2 extends A.Inner1 {
Inner2(boolean sel) {
(sel?a1:a2).super();
}
}
}
This case shows we can want to select enclosing instance for a base class constructor. Why selection logic should be so limited? Why one can't write something like this
if( sel ) {
a1.super();
}
else {
a2.super();
}
ADDITION
By my question I mean that the limitation could be like in the following case:
public class Base {
private final String content;
public Base(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
public class Derived extends Base {
public Derived(String content) {
super(String.format("Current value of content is %s.", getContent()));
}
}
In latter case I:
1) Fulfilling the requirement of super() to be in the first line
2) Violating the order of construction
3) Get a compiler error "Cannot refer to an instance method while explicitly invoking a constructor"
So, why we can't abolish "first line requirement" and rely only on errors like the last one?
Yes, a call to super() is required as the very first call in a constructor.
So much so that if you leave it out the compiler will (attempt to) insert the call for you. To understand the why, you would need to understand the philosophies of Java's designers. Gosling has always been in the camp of computer scientists that believe that accessing partially initialized objects is one of the bigger sources of bugs in computer programs. And as such he designed a strict initialization hierarchy that would help to alleviate this problem. Wether you agree with the philosophy is moot - but its important to realize that its as important a concept in Java as for example, references vs pointers, or real, bounded arrays. It should be noted that even languages like Objective C that allow you to invoke initialization at any time, go to great length to enforce initialization chaining, except that they need to do so via convention, as opposed to strict language rules.
I'm not sure what you were trying to illustrate in your example - but after years of development with Java I doubt you will find many cases where you really need to perform logic before invoking super.
Constructor calls are chained with super of every class in hierarchy being invoked before constructor of that class is invoked. As all classes in Java inherited from object class, so constructor of Object class is invoked first for every class with reason being that memory allocation for object is done by constructor of Object class
Let's look at the following code snippet in Java.
package trickyjava;
class A
{
public A(String s)
{
System.out.println(s);
}
}
final class B extends A
{
public B()
{
super(method()); // Calling the following method first.
}
private static String method()
{
return "method invoked";
}
}
final public class Main
{
public static void main(String[] args)
{
B b = new B();
}
}
By convention, the super() constructor in Java must be the first statement in the relevant constructor body. In the above code, we are calling the static method in the super() constructor parameter list itself super(method());.
It means that in the call to super in the constructor B(), a method is being
called BEFORE the call to super is made! This should be forbidden by the compiler but it works nice. This is somewhat equivalent to the following statements.
String s = method();
super(s);
However, it's illegal causing a compile-time error indicating that "call to super must be first statement in constructor". Why? and why it's equivalent super(method()); is valid and the compiler doesn't complain any more?
The key thing here is the static modifier. Static methods are tied to the class, instance methods (normal methods) are tied to an object (class instance). The constructor initializes an object from a class, therefore the class must already have been fully loaded. It is therefore no problem to call a static method as part of the constructor.
The sequence of events to load a class and create an object is like this:
load class
initialize static variables
create object
initialize object <-- with constructor
object is now ready for use
(simplified*)
By the time the object constructor is called, the static methods and variables are available.
Think of the class and its static members as a blueprint for the objects of that class. You can only create the objects when the blueprint is already there.
The constructor is also called the initializer. If you throw an exception from a constructor and print the stack trace, you'll notice it's called <init> in the stack frame. Instance methods can only be called after an object has been constructed. It is not possible to use an instance method as the parameter for the super(...) call in your constructor.
If you create multiple objects of the same class, steps 1 and 2 happen only once.
(*static initializers and instance initializers left out for clarity)
Yep, checking the JVM spec (though admittedly an old one):
In the instance init method, no reference to "this" (including the implicit reference of a return) may occur before a call to either another init method in the same class or an init method in the superclass has occurred.
This is really the only real restriction, so far as I can see.
The aim of requiring the super constructor to be invoked first is to ensure that the "super object" is fully initialized before it is used (It falls short of actually enforcing this because the super constructor can leak this, but that's another matter).
Calling a non-static method on this would allow the method to see uninitialized fields and is therefore forbidden. A static method can only see these fields if it is passed this as argument. Since accessing this and super is illegal in super constructor invocation expressions, and the call to super happens before the declaration of any variables that might point to this, allowing calls to static methods in super constructor invocation expressions is safe.
It is also useful, because it allows to compute the arguments to the super constructor in an arbitrarily complex manner. If calls to static methods weren't allowed, it would be impossible to use control flow statements in such a computation. Something as simple as:
class Sub extends Super {
Sub(Integer... ints) {
super(Arrays.asList(ints));
}
}
would be impossible.
This is one situation where the java syntax hides what's really going on, and C# makes it a bit clearer.
In C# your B would look like
class B : A {
public B() : base(method()) {
}
private static String method() {
return "method invoker";
}
}
Although the java syntax places super(method) within the constructor it's not really called there: All the parent initialization is run before your subclass constructor. The C# code shows this a little more clearly; by placing super(method()) at the first line of the java constructor you're simply telling java to use the parameterized constructor of the super class rather than the parameterless version; this way you can pass variables to the parent constructor and they'll be used in the initialization of the parent level fields before your child's constructor code runs.
The reason that super(method()) is valid (as the first line in a java constructor) is because method() is being loaded with the static elements--before the non-static ones, including the constructors--which allows it to be called not only before B(), but before A(String) as well. By saying
public B() {
String s = method();
super(s);
}
you're telling the java compiler to initialize the super object with the default constructor (because the call to super() isn't the first line) and you're ready to initialize the subclass, but the compiler then becomes confused when it sees that you're trying to initialize with super(String) after super() has already run.
A call to super is a must in java to allow the parent to get initalized before anything with child class starts.
In the case above, if java allows String s= method(); before the call to super, it opens up flood gate of things that can be done before a call to super. that would risk so many things, essentially that allows a half baked class to be used. Which is rightly not allowed. It would allow things like object state (some of which may belong to the parent) being modified before it was properly created.
In case of super(method()); call, we still adhere to the policy of completing parent initialization before child. and we can use a static member only, and static member of child classes are available before any child objects are created anyways. so the method is avilable and can be called.
OK..i think, this one could be relevant that, if we are calling some member with Super, then it first try to invoke in super class and if it doesn't find same one then it'll try to invoke the same in subclass.
PS: correct me if i'm wrong
I was wondering why in java constructors are not inherited? You know when you have a class like this:
public class Super {
public Super(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
this.serviceA = serviceA;
//etc
}
}
Later when you inherit from Super, java will complain that there is no default constructor defined. The solution is obviously something like:
public class Son extends Super{
public Son(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
super(serviceA,serviceB,serviceC);
}
}
This code is repetitive, not DRY and useless (IMHO)... so that brings the question again:
Why java doesn't support constructor inheritance? Is there any benefit in not allowing this inheritance?
Suppose constructors were inherited... then because every class eventually derives from Object, every class would end up with a parameterless constructor. That's a bad idea. What exactly would you expect:
FileInputStream stream = new FileInputStream();
to do?
Now potentially there should be a way of easily creating the "pass-through" constructors which are fairly common, but I don't think it should be the default. The parameters needed to construct a subclass are often different from those required by the superclass.
When you inherit from Super this is what in reality happens:
public class Son extends Super{
// If you dont declare a constructor of any type, adefault one will appear.
public Son(){
// If you dont call any other constructor in the first line a call to super() will be placed instead.
super();
}
}
So, that is the reason, because you have to call your unique constructor, since"Super" doesn't have a default one.
Now, trying to guess why Java doesn't support constructor inheritance, probably because a constructor only makes sense if it's talking about concrete instances, and you shouldn't be able to create an instance of something when you don't know how it's defined (by polymorphism).
Because constructing your subclass object may be done in a different way from how your superclass is constructed. You may not want clients of the subclass to be able to call certain constructors available in the superclass.
A silly example:
class Super {
protected final Number value;
public Super(Number value){
this.value = value;
}
}
class Sub {
public Sub(){ super(Integer.valueOf(0)); }
void doSomeStuff(){
// We know this.value is an Integer, so it's safe to cast.
doSomethingWithAnInteger((Integer)this.value);
}
}
// Client code:
Sub s = new Sub(Long.valueOf(666L)): // Devilish invocation of Super constructor!
s.doSomeStuff(); // throws ClassCastException
Or even simpler:
class Super {
private final String msg;
Super(String msg){
if (msg == null) throw new NullPointerException();
this.msg = msg;
}
}
class Sub {
private final String detail;
Sub(String msg, String detail){
super(msg);
if (detail == null) throw new NullPointerException();
this.detail = detail;
}
void print(){
// detail is never null, so this method won't fail
System.out.println(detail.concat(": ").concat(msg));
}
}
// Client code:
Sub s = new Sub("message"); // Calling Super constructor - detail is never initialized!
s.print(); // throws NullPointerException
From this example, you see that you'd need some way of declaring that "I want to inherit these constructors" or "I want to inherit all constructors except for these", and then you'd also have to specify a default constructor inheritance preference just in case someone adds a new constructor in the superclass... or you could just require that you repeat the constructors from the superclass if you want to "inherit" them, which arguably is the more obvious way of doing it.
Because constructors are an implementation detail - they're not something that a user of an interface/superclass can actually invoke at all. By the time they get an instance, it's already been constructed; and vice-versa, at the time you construct an object there's by definition no variable it's currently assigned to.
Think about what it would mean to force all subclasses to have an inherited constructor. I argue it's clearer to pass the variables in directly than for the class to "magically" have a constructor with a certain number of arguments just because it's parent does.
Constructors are not polymorphic.
When dealing with already constructed classes, you could be dealing with the declared type of the object, or any of its subclasses. That's what inheritance is useful for.
Constructor are always called on the specific type,eg new String(). Hypothetical subclasses have no role in this.
David's answer is correct. I'd like to add that you might be getting a sign from God that your design is messed up, and that "Son" ought not to be a subclass of "Super", but that, instead, Super has some implementation detail best expressed by having the functionality that Son provides, as a strategy of sorts.
EDIT: Jon Skeet's answer is awesomest.
Because a (super)class must have complete control over how it is constructed. If the programmer decides that it doesn't make sense to provide a default (no args) constructor as part of the class's contract, then the compiler should not provide one.
You essentially do inherit the constuctors in the sense that you can simply call super if and when appropriate, it's just that it would be error prone for reasons others have mentioned if it happened by default. The compiler can't presume when it is appropriate and when it isn't.
The job of the compiler is to provide as much flexibility as possible while reducing complexity and risk of unintended side-effects.
I don't know any language where subclasses inherit constructors (but then, I am not much of a programming polyglott).
Here's a discussion about the same question concerning C#. The general consensus seems to be that it would complicate the language, introduce the potential for nasty side effects to changes in a base class, and generally shouldn't be necessary in a good design.
A derived class is not the the same class as its base class and you may or may not care whether any members of the base class are initialized at the time of the construction of the derived class. That is a determination made by the programmer not by the compiler.
In a constructor in Java, if you want to call another constructor (or a super constructor), it has to be the first line in the constructor. I assume this is because you shouldn't be allowed to modify any instance variables before the other constructor runs. But why can't you have statements before the constructor delegation, in order to compute the complex value to the other function? I can't think of any good reason, and I have hit some real cases where I have written some ugly code to get around this limitation.
So I'm just wondering:
Is there a good reason for this limitation?
Are there any plans to allow this in future Java releases? (Or has Sun definitively said this is not going to happen?)
For an example of what I'm talking about, consider some code I wrote which I gave in this StackOverflow answer. In that code, I have a BigFraction class, which has a BigInteger numerator and a BigInteger denominator. The "canonical" constructor is the BigFraction(BigInteger numerator, BigInteger denominator) form. For all the other constructors, I just convert the input parameters to BigIntegers, and call the "canonical" constructor, because I don't want to duplicate all the work.
In some cases this is easy; for example, the constructor that takes two longs is trivial:
public BigFraction(long numerator, long denominator)
{
this(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));
}
But in other cases, it is more difficult. Consider the constructor which takes a BigDecimal:
public BigFraction(BigDecimal d)
{
this(d.scale() < 0 ? d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale())) : d.unscaledValue(),
d.scale() < 0 ? BigInteger.ONE : BigInteger.TEN.pow(d.scale()));
}
I find this pretty ugly, but it helps me avoid duplicating code. The following is what I'd like to do, but it is illegal in Java:
public BigFraction(BigDecimal d)
{
BigInteger numerator = null;
BigInteger denominator = null;
if(d.scale() < 0)
{
numerator = d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale()));
denominator = BigInteger.ONE;
}
else
{
numerator = d.unscaledValue();
denominator = BigInteger.TEN.pow(d.scale());
}
this(numerator, denominator);
}
Update
There have been good answers, but thus far, no answers have been provided that I'm completely satisfied with, but I don't care enough to start a bounty, so I'm answering my own question (mainly to get rid of that annoying "have you considered marking an accepted answer" message).
Workarounds that have been suggested are:
Static factory.
I've used the class in a lot of places, so that code would break if I suddenly got rid of the public constructors and went with valueOf() functions.
It feels like a workaround to a limitation. I wouldn't get any other benefits of a factory because this cannot be subclassed and because common values are not being cached/interned.
Private static "constructor helper" methods.
This leads to lots of code bloat.
The code gets ugly because in some cases I really need to compute both numerator and denominator at the same time, and I can't return multiple values unless I return a BigInteger[] or some kind of private inner class.
The main argument against this functionality is that the compiler would have to check that you didn't use any instance variables or methods before calling the superconstructor, because the object would be in an invalid state. I agree, but I think this would be an easier check than the one which makes sure all final instance variables are always initialized in every constructor, no matter what path through the code is taken. The other argument is that you simply can't execute code beforehand, but this is clearly false because the code to compute the parameters to the superconstructor is getting executed somewhere, so it must be allowed at a bytecode level.
Now, what I'd like to see, is some good reason why the compiler couldn't let me take this code:
public MyClass(String s) {
this(Integer.parseInt(s));
}
public MyClass(int i) {
this.i = i;
}
And rewrite it like this (the bytecode would be basically identical, I'd think):
public MyClass(String s) {
int tmp = Integer.parseInt(s);
this(tmp);
}
public MyClass(int i) {
this.i = i;
}
The only real difference I see between those two examples is that the "tmp" variable's scope allows it to be accessed after calling this(tmp) in the second example. So maybe a special syntax (similar to static{} blocks for class initialization) would need to be introduced:
public MyClass(String s) {
//"init{}" is a hypothetical syntax where there is no access to instance
//variables/methods, and which must end with a call to another constructor
//(using either "this(...)" or "super(...)")
init {
int tmp = Integer.parseInt(s);
this(tmp);
}
}
public MyClass(int i) {
this.i = i;
}
I think several of the answers here are wrong because they assume encapsulation is somehow broken when calling super() after invoking some code. The fact is that the super can actually break encapsulation itself, because Java allows overriding methods in the constructor.
Consider these classes:
class A {
protected int i;
public void print() { System.out.println("Hello"); }
public A() { i = 13; print(); }
}
class B extends A {
private String msg;
public void print() { System.out.println(msg); }
public B(String msg) { super(); this.msg = msg; }
}
If you do
new B("Wubba lubba dub dub");
the message printed out is "null". That's because the constructor from A is accessing the uninitialized field from B. So frankly it seems that if someone wanted to do this:
class C extends A {
public C() {
System.out.println(i); // i not yet initialized
super();
}
}
Then that's just as much their problem as if they make class B above. In both cases the programmer has to know how the variables are accessed during construction. And given that you can call super() or this() with all kinds of expressions in the parameter list, it seems like an artificial restriction that you can't compute any expressions before calling the other constructor. Not to mention that the restriction applies to both super() and this() when presumably you know how to not break your own encapsulation when calling this().
My verdict: This feature is a bug in the compiler, perhaps originally motivated by a good reason, but in its current form it is an artifical limitation with no purpose.
I find this pretty ugly, but it helps
me avoid duplicating code. The
following is what I'd like to do, but
it is illegal in Java ...
You could also work around this limitation by using a static factory method that returns a new object:
public static BigFraction valueOf(BigDecimal d)
{
// computate numerator and denominator from d
return new BigFraction(numerator, denominator);
}
Alternatively, you could cheat by calling a private static method to do the computations for your constructor:
public BigFraction(BigDecimal d)
{
this(computeNumerator(d), computeDenominator(d));
}
private static BigInteger computeNumerator(BigDecimal d) { ... }
private static BigInteger computeDenominator(BigDecimal d) { ... }
The constructors must be called in order, from the root parent class to the most derived class. You can't execute any code beforehand in the derived constructor because before the parent constructor is called, the stack frame for the derived constructor hasn't even been allocated yet, because the derived constructor hasn't started executing. Admittedly, the syntax for Java doesn't make this fact clear.
Edit: To summarize, when a derived class constructor is "executing" before the this() call, the following points apply.
Member variables can't be touched, because they are invalid before base
classes are constructed.
Arguments are read-only, because the stack frame has not been allocated.
Local variables cannot be accessed, because the stack frame has not been allocated.
You can gain access to arguments and local variables if you allocated the constructors' stack frames in reverse order, from derived classes to base classes, but this would require all frames to be active at the same time, wasting memory for every object construction to allow for the rare case of code that wants to touch local variables before base classes are constructed.
"My guess is that, until a constructor has been called for every level of the heierarchy, the object is in an invalid state. It is unsafe for the JVM to run anything on it until it has been completely constructed."
Actually, it is possible to construct objects in Java without calling every constructor in the hierarchy, although not with the new keyword.
For example, when Java's serialization constructs an object during deserialization, it calls the constructor of the first non-serializable class in the hierarchy. So when java.util.HashMap is deserialized, first a java.util.HashMap instance is allocated and then the constructor of its first non-serializable superclass java.util.AbstractMap is called (which in turn calls java.lang.Object's constructor).
You can also use the Objenesis library to instantiate objects without calling the constructor.
Or if you are so inclined, you can generate the bytecode yourself (with ASM or similar). At the bytecode level, new Foo() compiles to two instructions:
NEW Foo
INVOKESPECIAL Foo.<init> ()V
If you want to avoid calling the constructor of Foo, you can change the second command, for example:
NEW Foo
INVOKESPECIAL java/lang/Object.<init> ()V
But even then, the constructor of Foo must contain a call to its superclass. Otherwise the JVM's class loader will throw an exception when loading the class, complaining that there is no call to super().
Allowing code to not call the super constructor first breaks encapsulation - the idea that you can write code and be able to prove that no matter what someone else does - extend it, invoke it, instansiate it - it will always be in a valid state.
IOW: it's not a JVM requirement as such, but a Comp Sci requirement. And an important one.
To solve your problem, incidentally, you make use of private static methods - they don't depend on any instance:
public BigFraction(BigDecimal d)
{
this(appropriateInitializationNumeratorFor(d),
appropriateInitializationDenominatorFor(d));
}
private static appropriateInitializationNumeratorFor(BigDecimal d)
{
if(d.scale() < 0)
{
return d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale()));
}
else
{
return d.unscaledValue();
}
}
If you don't like having separate methods (a lot of common logic you only want to execute once, for instance), have one method that returns a private little static inner class which is used to invoke a private constructor.
My guess is that, until a constructor has been called for every level of the heierarchy, the object is in an invalid state. It is unsafe for the JVM to run anything on it until it has been completely constructed.
Well, the problem is java cannot detect what 'statements' you are going to put before the super call. For example, you could refer to member variables which are not yet initialized. So I don't think java will ever support this.
Now, there are many ways to work around this problem such as by using factory or template methods.
Look it this way.
Let's say that an object is composed of 10 parts.
1,2,3,4,5,6,7,8,9,10
Ok?
From 1 to 9 are in the super class, part #10 is your addition.
Simple cannot add the 10th part until the previous 9 are completed.
That's it.
If from 1-6 are from another super class that fine, the thing is one single object is created in a specific sequence, that's the way is was designed.
Of course real reason is far more complex than this, but I think this would pretty much answers the question.
As for the alternatives, I think there are plenty already posted here.