Why do this() and super() have to be the first statement in a constructor?

前端 未结 21 1920
北荒
北荒 2020-11-21 23:10

Java requires that if you call this() or super() in a constructor, it must be the first statement. Why?

For example:

public class MyClass {
    publi         


        
21条回答
  •  感情败类
    2020-11-21 23:45

    Can you give a code example where, if the compiler did not have this restriction, something bad would happen?

    class Good {
        int essential1;
        int essential2;
    
        Good(int n) {
            if (n > 100)
                throw new IllegalArgumentException("n is too large!");
            essential1 = 1 / n;
            essential2 = n + 2;
        }
    }
    
    class Bad extends Good {
        Bad(int n) {
            try {
                super(n);
            } catch (Exception e) {
                // Exception is ignored
            }
        }
    
        public static void main(String[] args) {
            Bad b = new Bad(0);
    //        b = new Bad(101);
            System.out.println(b.essential1 + b.essential2);
        }
    }
    

    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 neither essential1 nor essential2 are properly initialized.

    You may say that ignoring exceptions is always a bad idea. OK, here's another example:

    class Bad extends Good {
        Bad(int n) {
            for (int i = 0; i < n; i++)
                super(i);
        }
    }
    

    Funny, isn't it? How many objects are we creating in this example? One? Two? Or maybe nothing...

    Allowing to call super() or this() 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() or this(). This might be any code not relying on this reference (which, in fact, already exists at the very beginning of a constructor, but cannot be used orderly until super() or this() 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 to super() or this() will be needed after it.

    In such cases, you have the following opportunities:

    1. Use the pattern presented at this answer, which allows to circumvent the restriction.
    2. Wait for the Java team to allow pre-super() and pre-this() code. It may be done by imposing a restriction on where super() or this() 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 that super() and this() return this reference and, in turn, your constructor has

    return this;
    

    at the end. As well as the compiler rejects the code

    public int get() {
        int x;
        for (int i = 0; i < 10; i++)
            x = i;
        return x;
    }
    
    public int get(int y) {
        int x;
        if (y > 0)
            x = y;
        return x;
    }
    
    public int get(boolean b) {
        int x;
        try {
            x = 1;
        } catch (Exception e) {
        }
        return x;
    }
    

    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 is this cannot be assigned by any means other than super() or this() 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 first get(), where x 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 before super() or this().

提交回复
热议问题