Multiple Super( ) for overloading super class constructor - java

class Time
{
public static void main (String args[])
{
Son obj = new Son();
}
}
class Father // Super Class
{
Father(int x, int y) // parameterized constructor
{
int a = x;
int b = y;
System.out.println("Super Class Constructor a = "+a);
System.out.println("Super Class Constructor b = "+b);
}
Father(int z) // parameterized constructor
{
int d = z;
System.out.println("Super Class Constructor d = "+d);
}
}
class Son extends Father // Sub Class
{
Son() // default constructor
{
super(100);
super(10, 20); // Problem is here
int c = 200;
System.out.println("Sub Class Constructor c = "+c);
}
}
My question is can we use multiple super ( ) in subclass constructor as i want to initialize two super class Parameterized constructor. If it is not possible then how can i do this?

Your code is simply wrong. A constructor in Java has to always call exactly one super class constructor. There is no such thing as writing down super() twice in the same constructor.
In other words: the very first statement in a constructor is a call to a super-class constructor. If you don't put such a call there, the compiler will insert a call to super() behind the covers.
In that sense: when you are a beginner, and the compiler gives you an error message; the thing to do: turn to a good book or online resource.

My polemic answer is you don’t want to do that (feel free to challenge me). You want to design you superclass (Father) in such a way that it only takes one super constructor call to construct and initialize it so that it is ready for use.
In your example you haven’t got any fields in Father, so any of your constructors should be good enough for that. if you’re happy with the constructors you have but still want the output from both, there are a couple of options. First, you may add a three-arg constructor Father(int x, int y, int z) as Nghia Do suggested in a comment. You don’t need to delete the other two constructors if you prefer to have all three. Second, you may put in a method call instead of the second super call, and write a method in Father to print the message and do what other work you require. For the sake of code reuse, you ought to have the two-arg constructor call the same method rather than having the code duplicated.
Think what would happen if you had a class with two constructors and you needed to call both — if that was allowed. This would be a tricky bug waiting to happen. There would always be a risk that someone forgot to call both. You’d end up with some half-constructed object, and no one would know when something would go wrong when you used it.And when that happened, it would be far from obvious that it was due to the forgotten second constructor call. As I said, you don’t want that. The rule that Java always calls exactly one super constructor is a good one.

Related

How should i solve a problem with needing to call this() and super() at the same time?

Okay, so, I have a kind of specific problem. I have a class structure similar to this (simplified for simplicity purposes).
class A {
A() {
// long initialization
}
A(int someValue) {
this();
// do something with someValue
}
}
class B extends A {
B() {
super();
// some long initialization
}
B(int someValue) {
// What should i do here ?
}
}
But now, i want to be able to construct class B using the second constructor. But the second constructor should call the super(someValue) constructor to make use of the someValue parameter, but at the same time it needs to call this() to to not have to duplicate the initialization of this class. The problem is that i can't call this and super constructors at the same time.
Also I can't extract the initialization in first constructor to some method, because I have some final fields that needs to be initialized inside the constructor to stay final.
The usual solution is to flip the dependencies between your constructor: call super(someValue) inside B(int someValue), and call this(DEFAULT) inside B(). However, you’ll need to figure out a valid DEFAULT for this case — that is, a default value for someValue that can be used by the parameter-less B() constructor (null often works).
If A() and A(int someValue) do fundamentally different things this won’t work, but that’s a sign that the class A is probably poorly designed (in other words: it should be feasible).
As an alternative, just have both B() and B(int someValue) call a method that performs the rest of the initialisation, after calling super()/super(someValue).

Cannot pass super keyword as an argument to method in java

Why below program does not work fine?
instead of super in below code if we give this keyword as an argument it will work fine, what is the difference between two codes.
Thanks in advance
class Vehicle
{
int maxSpeed = 120;
}
/* subclass Car extending vehicle */
class Car extends Vehicle
{
int maxSpeed = 180;
void display()
{
test(super);
/* print maxSpeed of base class (vehicle) */
// System.out.println("Maximum Speed: " + super.maxSpeed);
}
public void test(Vehicle obj)
{
System.out.println("Maximum Speed: " + obj.maxSpeed);
}
}
/* Driver program to test */
class Test
{
public static void main(String[] args)
{
Car small = new Car();
small.display();
}
}
There is a misconception on your end. this refences to a real object, therefore you can pass it to any method that allows for an instance of the corresponding class.
But there is no separate super object! super is nothing but a helper mechanism that allows you to access methods or fields of the super class (and it only works within a derived class). It is not intended to deliver a real object refence!
And note: that also doesn't make sense conceptually. You can't really separate the super class properties when looking at a child class due to polymorphism.
It is really simple: you pass this, nothing else. If your code doesn't work then, then that would be a symptom of a bug in your design!
Welcome to StackOverflow.
Your method test receives a instance of a Car, and keyword super it's used to call parent methods, through child class. this keyword returns the instance of the class.
What you're trying to achieve is call super() constructor to pass a instance of a Car to the method, but java states that the the super() call can be used only once in the constructor class as the first statement, to ensure that class will inherit from it's parent, or Object class directly. If you not states it, Java implicitly does it for you.

What happens if you call an overridden method using super in a constructor

There is two classes Super1 and Sub1
Super1.class
public class Super1 {
Super1 (){
this.printThree();
}
public void printThree(){
System.out.println("Print Three");
}
}
Sub1.class
public class Sub1 extends Super1 {
Sub1 (){
super.printThree();
}
int three=(int) Math.PI;
public void printThree(){
System.out.println(three);
}
public static void main(String ...a){
new Sub1().printThree();
}
}
When I invoke the method printThree of class Sub1 I expected the output to be:
Print Three
3
Because Sub1 constructor calling the super.printThree();.
But I actually get
0
Print Three
3
I know 0 is default value of int but how it is happening ?
You're seeing the effects of three things:
Default super-constructor calls, and
Instance initializers relative to super calls, and
How overridden methods work
Your Sub1 constructor is really this:
Sub1(){
super(); // <== Default super() call, inserted by the compiler
three=(int) Math.PI; // <== Instance initializers are really inserted
// into constructors by the compiler
super.printThree();
}
(Surprising, I know, but it's true. Use javap -c YourClass to look. :-) )
The reason it looks like that is that the superclass must have a chance to initialize its part of the object before the subclass can initialize its part of the object. So you get this kind of interwoven effect.
And given that that's what Sub1 really looks like, let's walk through it:
The JVM creates the instance and sets all instance fields to their defaults (all bits off). So at this point, the three field exists, and has the value 0.
The JVM calls Sub1.
Sub1 immediately calls super() (Super1), which...
...calls printThree. Since printThree is overridden, even though the call to it is in the code for Super1, it's the overridden method (the one in Sub1) that gets called. This is part of how Java implements polymorphism. Since three's instance initializer hasn't been run yet, three contains 0, and that's what gets output.
Super1 returns.
Back in Sub1, the instance initializer code for three that the compiler inserted (relocated, really) runs and gives three a new value.
Sub1 calls printThree. Since three's instance initializer code has now run, printThree prints 3.
With regard to this instance initializer code getting moved into the constructor, you might be wondering: What if I have more than one constructor? Which one does the code get moved into? The answer is that the compiler duplicates the code into each constructor. (You can see that in javap -c, too.) (If you have a really complicated instance initializer, I wouldn't be surprised if the compiler effectively turned it into a method, but I haven't looked.)
It's a bit clearer if you do something really naughty and call a method during your instance init: (live copy)
class Super
{
public static void main (String[] args) {
new Sub();
}
Super() {
System.out.println("Super constructor");
this.printThree();
}
protected void printThree() {
System.out.println("Super's printThree");
}
}
class Sub extends Super
{
int three = this.initThree();
Sub() {
this.printThree();
}
private int initThree() {
System.out.println("Sub's initThree");
return 3;
}
protected void printThree() {
System.out.println("Sub's printThree: " + this.three);
}
}
Output:
Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3
Note where "Sub's initThree" came in that sequence.
When the instance is created, the Sub1 constructor is called.
The first instruction in any constructor is a call to the superclass constructor. If you don't have an explicit call, there will be an implicit call to the no-args constructor of Super1.
The no-args constructor is calling this.printThree(). This method is overridden in Sub1. Now, this part may be confusing, but even if the code is in the superclass, this.method() still refers to the overriding method.
So it's calling the printThree() in Sub1, which prints the uninitialized value of the variable three - 0.
Now that the superclass's constructor is done, it completes Sub1 constructor, which uses super.printThree(). Since it specifically says super, the method from Super1 is used rather than the overriding one. This prints the Print Three.
Now the Sub1 constructor is also done, and main calls the new instance's printThree(). Now three is already initialized, so you get the output 3.
While previous answers gave you clear answer to what is happening, they did not gave you any pointers on how to avoid your problems in the future, so I would also like to add my input on this.
If you are going to inherit, then you should make the super class constructor as "dumb" as possible. For example
public class Super{
private int a,b;
public Super(int a, int b) {
this.a = a;
this.b = b;
}
//all the methods operating on the data provided by constructor
}
and then having sub constructor like this
private int c,d;
public Sub(int a, int b) {
super(a,b);
c = a;
d = b;
}
Is perfectly fine and is going to give you minimal side-effects, while keeping the functionality of the parent class.
But having
public Super(){
method1();
method2();
}
and then having sub do this
public Sub(){
super.method1();
super.method2();
}
Is really asking for trouble and possible hard to track bugs. The less the object does during initialization, the better, because it gives the childs flexibility.
Managing inheritance is like being dumb manager vs clever manager. Dumb manager calls Tim and Tracy employee, because they are both employees, and their jobs as Accountant and HR manager are just tags. Clever manager knows Tim and Tracy are Accountant and Manager and does not care that much that they are basically just employees.

Java - Extends issue

I am having a hell of a time with an "extends" issue with a problem in a problem set I'm working on - I think I'm just having a block because it's written to be purposefully confusing. Here's the problem as I was given it:
class A {
int x;
A(int a) {System.out.println(" class A");}
}
class B extends A {
int x;
B() {System.out.println(" class B");}
public static void main (String [] args) {
A a = new B();
}
}
When I compile, I get the following error kicked out from the console:
cannot find symbol
symbol : constructor A()
location: class A
B() {System.out.println(" class B");}
^
and I'm supposed to be able to fix this error in class B without touching class A. I'm clearly missing something stupidly obvious, but I've tried permutations of everything I can think of for an hour and nothing's working.
So far, I've tried:
throwing a void in front of B() - same error.
making B() into A(int a) - the latter comes back with an invalid method declaration error (adding a void in front of it kicks me back to the original "cannot find symbol" error)
making B() B(int a) - same error, plus throws an additional "cannot find symbol" error since I've now trashed the B() declaration.
making class B extends A into class B extends A(int A) - throws nine errors. Clearly not the answer.
Changing the class name of A to Apple just to see if that would give me an answer - this wants me to add a void in front of A(int a) in the Apple class, which I can't do.
What the hell am I missing here? This is not exactly an advanced class so it can't be anything terribly complicated, but this is making me completely insane. Any help would be greatly appreciated.
In a derived class, you need to call the base class constructor. If you don't do this explicitly, the compiler will try and insert a call to the no-argument constructor - if none exists in the base class, you get that error.
The solution is to explicitly call the base class constructor with some value:
B() {
super(0);
System.out.println(" class B");
}
your first call in B's constructor needs to be super(a);
a being whatever you want to input into B's constructor.
1) When you extend a class, your subclass implicitly contains a chunk of data that consists of all the data used to make an instance of the superclass. You have to initialize that data, too. If you don't say how it will be initialized, it is assumed you want the default constructor, i.e. A.A(). But this constructor does not exist - you only have A.A(int).
To do this initialization, as the first line in the B constructor, you make a call to the A constructor, with special syntax as follows:
B() {
super(42);
// because we are calling the constructor that takes an int, we must supply
// one. It's up to you to figure out what values should be supplied. Maybe
// you wanted to take an int in the B constructor, and pass it along?
System.out.println(" class B");
}
2) You have an int x; declared in both class A and class B. This is probably not what you want. As noted, each B instance already contains an int x - the one that it automatically gets because B extends A.
Class A does not have a default constructor because you didn't write one (but you did write one that takes an int parameter).
Class B has a no-arg default constructor. It needs to call a superclass constructor, but it can't because there is no such thing in class A.

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

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?
The parent class' constructor needs to be called before the subclass' constructor. This will ensure that if you call any methods on the parent class in your constructor, the parent class has already been set up correctly.
What you are trying to do, pass args to the super constructor is perfectly legal, you just need to construct those args inline as you are doing, or pass them in to your constructor and then pass them to super:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
super(myArray);
}
}
If the compiler did not enforce this you could do this:
public MySubClassB extends MyClass {
public MySubClassB(Object[] myArray) {
someMethodOnSuper(); //ERROR super not yet constructed
super(myArray);
}
}
In cases where a parent class has a default constructor the call to super is inserted for you automatically by the compiler. Since every class in Java inherits from Object, objects constructor must be called somehow and it must be executed first. The automatic insertion of super() by the compiler allows this. Enforcing super to appear first, enforces that constructor bodies are executed in the correct order which would be: Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth
I've found a way around this by chaining constructors and static methods. What I wanted to do looked something like this:
public class Foo extends Baz {
private final Bar myBar;
public Foo(String arg1, String arg2) {
// ...
// ... Some other stuff needed to construct a 'Bar'...
// ...
final Bar b = new Bar(arg1, arg2);
super(b.baz()):
myBar = b;
}
}
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:
public class Foo extends Baz {
private final Bar myBar;
private static Bar makeBar(String arg1, String arg2) {
// My more complicated setup routine to actually make 'Bar' goes here...
return new Bar(arg1, arg2);
}
public Foo(String arg1, String arg2) {
this(makeBar(arg1, arg2));
}
private Foo(Bar bar) {
super(bar.baz());
myBar = bar;
}
}
Legal code, and it accomplishes the task of executing multiple statements before calling the super constructor.
Because the JLS says so. Could the JLS be changed in a compatible manner to allow it? Yup.
However, it would complicate the language spec, which is already more than complicated enough. It wouldn't be a highly useful thing to do and there are ways around it (call another constructor with the result of a static method or lambda expression this(fn()) - the method is called before the other constructor, and hence also the super constructor). So the power to weight ratio of doing the change is unfavourable.
Note that this rule alone does not prevent use of fields before the super class has completed construction.
Consider these illegal examples.
super(this.x = 5);
super(this.fn());
super(fn());
super(x);
super(this instanceof SubClass);
// this.getClass() would be /really/ useful sometimes.
This example is legal, but "wrong".
class MyBase {
MyBase() {
fn();
}
abstract void fn();
}
class MyDerived extends MyBase {
void fn() {
// ???
}
}
In the above example, if MyDerived.fn required arguments from the MyDerived constructor they would need to be sleazed through with a ThreadLocal. ;(
Incidentally, since Java 1.4, the synthetic field that contains the outer this is assigned before inner classes super constructor is called. This caused peculiar NullPointerException events in code compiled to target earlier versions.
Note also, in the presence of unsafe publication, construction can be viewed reordered by other threads, unless precautions are made.
Edit March 2018: In message Records: construction and validation Oracle is suggesting this restriction be removed (but unlike C#, this will be definitely unassigned (DU) before constructor chaining).
Historically, this() or super() must be first in a constructor. This
restriction was never popular, and perceived as arbitrary. There were
a number of subtle reasons, including the verification of
invokespecial, that contributed to this restriction. Over the years,
we've addressed these at the VM level, to the point where it becomes
practical to consider lifting this restriction, not just for records,
but for all constructors.
Simply because this is the inheritance philosophy. And according to the Java language specification, this is how the constructor's body is defined:
ConstructorBody:
{ ExplicitConstructorInvocationopt BlockStatementsopt }
The first statement of a constructor body may be either
an explicit invocation of another constructor of the same class (by using the keyword "this"); or
an explicit invocation of the direct superclass (by using the keyword "super")
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. And so on.. there will be a whole chain of constructors called all the way back to the constructor of Object; "All Classes in the Java platform are Descendants of Object". This thing is called "Constructor Chaining".
Now why is this?
And the reason why Java defined the ConstructorBody in this way, is that they needed to maintain the hierarchy of the object. Remember the definition of the inheritance; It's extending a class. With that being said, you cannot extend something that doesn't exist. The base (the superclass) needs to be created first, then you can derive it (the subclass). That's why they called them Parent and Child classes; you can't have a child without a parent.
On a technical level, a subclass inherits all the members (fields, methods, nested classes) from its parent. And since Constructors are NOT members (They don't belong to objects. They are responsible of creating objects) so they are NOT inherited by subclasses, but they can be invoked. And since at the time of object creation only ONE constructor is executed. So how do we guarantee the creation of the superclass when you create the subclass object? Thus the concept of "constructor chaining"; so we have the ability to invoke other constructors (i.e. super) from within the current constructor. And Java required this invocation to be the FIRST line in the subclass constructor to maintain the hierarchy and guarantee it. They assume that if you don't explicitly create the parent object FIRST (like if you forgot about it), they will do it implicitly for you.
This check is done during compilation. But I'm not sure what would happen on runtime, what kind of runtime error we would get, IF Java doesn't throw a compile-error when we explicitly try to execute a base constructor from within a subclass's constructor in the middle of its body and not from the very first line ...
I am fairly sure (those familiar with the Java Specification chime in) that it is to prevent you from (a) being allowed to use a partially-constructed object, and (b), forcing the parent class's constructor to construct on a "fresh" object.
Some examples of a "bad" thing would be:
class Thing
{
final int x;
Thing(int x) { this.x = x; }
}
class Bad1 extends Thing
{
final int z;
Bad1(int x, int y)
{
this.z = this.x + this.y; // WHOOPS! x hasn't been set yet
super(x);
}
}
class Bad2 extends Thing
{
final int y;
Bad2(int x, int y)
{
this.x = 33;
this.y = y;
super(x); // WHOOPS! x is supposed to be final
}
}
You asked why, and the other answers, imo, don't really say why it's ok to call your super's constructor, but only if it's the very first line. The reason is that you're not really calling the constructor. In C++, the equivalent syntax is
MySubClass: MyClass {
public:
MySubClass(int a, int b): MyClass(a+b)
{
}
};
When you see the initializer clause on its own like that, before the open brace, you know it's special. It runs before any of the rest of the constructor runs and in fact before any of the member variables are initialized. It's not that different for Java. There's a way to get some code (other constructors) to run before the constructor really starts, before any members of the subclass are initialized. And that way is to put the "call" (eg super) on the very first line. (In a way, that super or this is kind of before the first open brace, even though you type it after, because it will be executed before you get to the point that everything is fully constructed.) Any other code after the open brace (like int c = a + b;) makes the compiler say "oh, ok, no other constructors, we can initialize everything then." So it runs off and initializes your super class and your members and whatnot and then starts executing the code after the open brace.
If, a few lines later, it meets some code saying "oh yeah when you're constructing this object, here are the parameters I want you to pass along to the constructor for the base class", it's too late and it doesn't make any sense. So you get a compiler error.
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.
Actually you can execute logic with several expessions, you just have to wrap your code in a static function and call it in the super statement.
Using your example:
public class MySubClassC extends MyClass {
public MySubClassC(Object item) {
// Create a list that contains the item, and pass the list to super
super(createList(item)); // OK
}
private static List createList(item) {
List list = new ArrayList();
list.add(item);
return list;
}
}
I totally agree, the restrictions are too strong. Using a static helper method (as Tom Hawtin - tackline suggested) or shoving all "pre-super() computations" into a single expression in the parameter is not always possible, e.g.:
class Sup {
public Sup(final int x_) {
//cheap constructor
}
public Sup(final Sup sup_) {
//expensive copy constructor
}
}
class Sub extends Sup {
private int x;
public Sub(final Sub aSub) {
/* for aSub with aSub.x == 0,
* the expensive copy constructor is unnecessary:
*/
/* if (aSub.x == 0) {
* super(0);
* } else {
* super(aSub);
* }
* above gives error since if-construct before super() is not allowed.
*/
/* super((aSub.x == 0) ? 0 : aSub);
* above gives error since the ?-operator's type is Object
*/
super(aSub); // much slower :(
// further initialization of aSub
}
}
Using an "object not yet constructed" exception, as Carson Myers suggested, would help, but checking this during each object construction would slow down execution. I would favor a Java compiler that makes a better differentiation (instead of inconsequently forbidding an if-statement but allowing the ?-operator within the parameter), even if this complicates the language spec.
I found a woraround.
This won't compile :
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
int c = a + b;
super(c); // COMPILE ERROR
doSomething(c);
doSomething2(a);
doSomething3(b);
}
}
This works :
public class MySubClass extends MyClass {
public MySubClass(int a, int b) {
this(a + b);
doSomething2(a);
doSomething3(b);
}
private MySubClass(int c) {
super(c);
doSomething(c);
}
}
My guess is they did this to make life easier for people writing tools that process Java code, and to some lesser degree also people who are reading Java code.
If you allow the super() or this() call to move around, there are more variations to check for. For example if you move the super() or this() call into a conditional if() it might have to be smart enough to insert an implicit super() into the else. It might need to know how to report an error if you call super() twice, or use super() and this() together. It might need to disallow method calls on the receiver until super() or this() is called and figuring out when that is becomes complicated.
Making everyone do this extra work probably seemed like a greater cost than benefit.
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:
Use the pattern presented at this answer, which allows to circumvent the restriction.
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().
You can use anonymous initializer blocks to initialize fields in the child before calling it's constructor. This example will demonstrate :
public class Test {
public static void main(String[] args) {
new Child();
}
}
class Parent {
public Parent() {
System.out.println("In parent");
}
}
class Child extends Parent {
{
System.out.println("In initializer");
}
public Child() {
super();
System.out.println("In child");
}
}
This will output :
In parent
In initializer
In child
It makes sense that constructors complete their execution in order of
derivation. Because a superclass has no knowledge of any subclass, any
initialization it needs to perform is separate from and possibly
prerequisite to any initialization performed by the subclass.
Therefore, it must complete its execution first.
A simple demonstration:
class A {
A() {
System.out.println("Inside A's constructor.");
}
}
class B extends A {
B() {
System.out.println("Inside B's constructor.");
}
}
class C extends B {
C() {
System.out.println("Inside C's constructor.");
}
}
class CallingCons {
public static void main(String args[]) {
C c = new C();
}
}
The output from this program is:
Inside A's constructor
Inside B's constructor
Inside C's constructor
I know I am a little late to the party, but I've used this trick a couple of times (and I know it's a bit unusual):
I create an generic interface InfoRunnable<T> with one method:
public T run(Object... args);
And if I need to do something before passing it to the constructor I just do this:
super(new InfoRunnable<ThingToPass>() {
public ThingToPass run(Object... args) {
/* do your things here */
}
}.run(/* args here */));
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 have super() in your first statement, the compiler will add it for you!
That's because your constructor depends on other constructors. To your constructor work correctly its necessary to other constructor works correctly which is dependent. That's why its necessary to check dependent constructors first which called by either this() or super() in your constructor. If other constructors which called by either this() or super() have a problem so whats point execute other statements because all will fail if called constructor fails.
The question of why Java does this has already been answered, but since I stumbled upon this question hoping to find a better alternative to the one-liner, I'll hereby share my work-around:
public class SomethingComplicated extends SomethingComplicatedParent {
private interface Lambda<T> {
public T run();
}
public SomethingComplicated(Settings settings) {
super(((Lambda<Settings>) () -> {
// My modification code,
settings.setting1 = settings.setting2;
return settings;
}).run());
}
}
Calling a static function should perform better, but I would use this if I insist on having the code "inside" the constructor, or if I have to alter multiple parameters and find defining many static methods bad for readability.
This is official replay:
Historically, this() or super() must be first in a constructor. This
restriction was never popular, and perceived as arbitrary. There were a
number of subtle reasons, including the verification of invokespecial,
that contributed to this restriction. Over the years, we've addressed
these at the VM level, to the point where it becomes practical to
consider lifting this restriction, not just for records, but for all
constructors.
Tldr:
The other answers have tackled the "why" of the question. I'll provide a hack around this limitation:
The basic idea is to hijack the super statement with your embedded statements. This can be done by disguising your statements as expressions.
Tsdr:
Consider we want to do Statement1() to Statement9() before we call super():
public class Child extends Parent {
public Child(T1 _1, T2 _2, T3 _3) {
Statement_1();
Statement_2();
Statement_3(); // and etc...
Statement_9();
super(_1, _2, _3); // compiler rejects because this is not the first line
}
}
The compiler will of course reject our code. So instead, we can do this:
// This compiles fine:
public class Child extends Parent {
public Child(T1 _1, T2 _2, T3 _3) {
super(F(_1), _2, _3);
}
public static T1 F(T1 _1) {
Statement_1();
Statement_2();
Statement_3(); // and etc...
Statement_9();
return _1;
}
}
The only limitation is that the parent class must have a constructor which takes in at least one argument so that we can sneak in our statement as an expression.
Here is a more elaborate example:
public class Child extends Parent {
public Child(int i, String s, T1 t1) {
i = i * 10 - 123;
if (s.length() > i) {
s = "This is substr s: " + s.substring(0, 5);
} else {
s = "Asdfg";
}
t1.Set(i);
T2 t2 = t1.Get();
t2.F();
Object obj = Static_Class.A_Static_Method(i, s, t1);
super(obj, i, "some argument", s, t1, t2); // compiler rejects because this is not the first line
}
}
Reworked into:
// This compiles fine:
public class Child extends Parent {
public Child(int i, String s, T1 t1) {
super(Arg1(i, s, t1), Arg2(i), "some argument", Arg4(i, s), t1, Arg6(i, t1));
}
private static Object Arg1(int i, String s, T1 t1) {
i = Arg2(i);
s = Arg4(s);
return Static_Class.A_Static_Method(i, s, t1);
}
private static int Arg2(int i) {
i = i * 10 - 123;
return i;
}
private static String Arg4(int i, String s) {
i = Arg2(i);
if (s.length() > i) {
s = "This is sub s: " + s.substring(0, 5);
} else {
s = "Asdfg";
}
return s;
}
private static T2 Arg6(int i, T1 t1) {
i = Arg2(i);
t1.Set(i);
T2 t2 = t1.Get();
t2.F();
return t2;
}
}
In fact, compilers could have automated this process for us. They'd just chosen not to.
Before you can construct child object your parent object has to be created.
As you know when you write class like this:
public MyClass {
public MyClass(String someArg) {
System.out.println(someArg);
}
}
it turns to the next (extend and super are just hidden):
public MyClass extends Object{
public MyClass(String someArg) {
super();
System.out.println(someArg);
}
}
First we create an Object and then extend this object to MyClass. We can not create MyClass before the Object.
The simple rule is that parent's constructor has to be called before child constructor.
But we know that classes can have more that one constructor. Java allow us to choose a constructor which will be called (either it will be super() or super(yourArgs...)).
So, when you write super(yourArgs...) you redefine constructor which will be called to create a parent object. You can't execute other methods before super() because the object doesn't exist yet (but after super() an object will be created and you will be able to do anything you want).
So why then we cannot execute this() after any method?
As you know this() is the constructor of the current class. Also we can have different number of constructors in our class and call them like this() or this(yourArgs...). As I said every constructor has hidden method super(). When we write our custom super(yourArgs...) we remove super() with super(yourArgs...). Also when we define this() or this(yourArgs...) we also remove our super() in current constructor because if super() were with this() in the same method, it would create more then one parent object.
That is why the same rules imposed for this() method. It just retransmits parent object creation to another child constructor and that constructor calls super() constructor for parent creation.
So, the code will be like this in fact:
public MyClass extends Object{
public MyClass(int a) {
super();
System.out.println(a);
}
public MyClass(int a, int b) {
this(a);
System.out.println(b);
}
}
As others say you can execute code like this:
this(a+b);
also you can execute code like this:
public MyClass(int a, SomeObject someObject) {
this(someObject.add(a+5));
}
But you can't execute code like this because your method doesn't exists yet:
public MyClass extends Object{
public MyClass(int a) {
}
public MyClass(int a, int b) {
this(add(a, b));
}
public int add(int a, int b){
return a+b;
}
}
Also you are obliged to have super() constructor in your chain of this() methods. You can't have an object creation like this:
public MyClass{
public MyClass(int a) {
this(a, 5);
}
public MyClass(int a, int b) {
this(a);
}
}
class C
{
int y,z;
C()
{
y=10;
}
C(int x)
{
C();
z=x+y;
System.out.println(z);
}
}
class A
{
public static void main(String a[])
{
new C(10);
}
}
See the example if we are calling the constructor C(int x) then value of z is depend on y if we do not call C() in the first line then it will be the problem for z. z would not be able to get correct value.
The main goal of adding the super() in the sub-class constructors is that the main job of the compiler is to make a direct or indirect connection of all the classes with the Object class that's why the compiler checks if we have provided the super(parameterized) then compiler doesn't take any responsibility.
so that all the instance member gets initialized from Object to the sub - classes.

Categories

Resources