I am getting an error with this following code fragment
The error is : cannot reference x before supertype constructor has been called (and pointing out the statement at comment 1)
class Con{
int x =10;
Con(){
this(++x); //1
System.out.println("x :"+x);
}
Con(int i){
x=i++;
System.out.println("x :"+x);
}
}
In the main method I have this statement
Con c1=new Con();
I don't understand the error. Can someone explain what is actually happening here?
When creating an instance of a class, the constructor first calls it's super class constructor to initialize the super class fields. Once all the super class constructors have run, then only the current constructor continues to initialize it's own field.
Now, when you add a this() call in your constructor, it doesn't call the super class constructor. This is because, the first statement in a constructor is either a chain to super class constructor - using super(), or a different constructor of the same class - using this().
So, you can't pass the field in this(), because the field is isn't initialized yet. But it doesn't really make sense, why you are trying to do something like that?
Remember, the compiler moves the field initialization code inside each constructor of your class. So, your constructor is effectively equivalent to:
Con() {
this(++x); //1
// This is where initialization is done. You can't access x before it.
x = 10;
System.out.println("x :"+x);
}
This is true even with super() call. So, the below code will also give you the same error (considering Con extends another class with a parameterized constructor):
Con() {
super(++x); //1
System.out.println("x :"+x);
}
Con(){
this(++x); //1
System.out.println("x :"+x);
}
At this very moment, Con does not yet exist. It first instantiates by calling the other constructor. That means that x does not exist yet (it is created as soon as the other constructor instantiates). So you can't reference it yet.
If you really need to reference it, you have to use a static variable
private static int x = 10;
First call inside a constructor can only be this() or super() , if their is none of them then compiler automatically insert a call to super but in your constructor you called other constructor by using this() . basically whenever you construct an object the superclass is first initialized then the subclass's members gets initialized.So you can not refer to uninitialized members as they gets initialized after superclass's members and superclass itself.
Related
I tried to go through almost every article here about variable initializations, but I still do not understand couple things about it. It is not clear for me if we HAVE TO call the constructor to initialize the instance variables to default values or it can happen without invoking the constructor? For example, convention is that every class written by us in Java is invoking a super class constructor in its constructor to "initialize variables" of super class. What does it exactly mean? Do we have to invoke a super class constructor to initialize instance variables of super class to default values? Or even without invokin super class constructor instance variables have an default values, and we are doing this to pass them the values described in constructor or given during the declaration? The second thing is, that we can initialize variables in couple ways, by not giving them a values (they will be set to default values), giving values in declaration, for example:
private int number = 10;
or specifing values in a constructor. It is clear for me, that we have to invoke the constructor to initialize variables to values specified in constructor but what about other 2 examples? Do we also have to invoke constructor to initialize instance variable to these values? Can someone also give me an order for creating this in simple words? I know that there are a lot of articles here about order of object instantiation and initialization and i have read them all, but I still do not understand a lot of things there.
And tell me if I am wrong, but what I understanded, the answer to question is that we have to invoke a super class constructor to initialize super class fields to their default values because in the other way there will be no point to making a call the super class constructors necessary if the instance variables of super class would be already initialized with default values without calling the constructor - because we wouldnt have to worry that our variables are uninitialized if they are - with default values.
#EDIT: To be clear, my main question was:
When instance variables are getting a default value? In the constructor or before the constructor? Do constructor have to be called to initialize the instance variables, or the default values are assigned even before the constructor call?
In an Object Oriented Programming Languages "Object" plays the Key role. So, initiating the object is must. I couldn't exactly get what you are asking.. I'm telling according to my knowledge.
You have to instantiate a class to use its fields & methods. For that you are assigning like this
Class_Name object = new Class_Name();
no problem whether you are creating a default constructor in the invoking class it will creates a default one.
But, once you created a constructor with parameters you have to create a default constructor to initiate an Object like above.
You may assign values to variables in the class as you described & through parameterized constructors. Its best to write private modifier for initiating a variable (here comes Encapsulation Concept).
You can change the value of the instantiated variable through passing a parameter in constructor.
If you haven't put any values for your variables. Compiler will put a default value for that.
Have a look at this article
https://www.javaworld.com/article/2076614/core-java/object-initialization-in-java.html
According to JLS 4.12.5:
Every variable in a program must have a value before its value is
used:
Each class variable, instance variable, or array component is
initialized with a default value when it is created (§15.9, §15.10.2):
For type byte, the default value is zero, that is, the value of
(byte)0.
For type short, the default value is zero, that is, the value of
(short)0.
For type int, the default value is zero, that is, 0.
For type long, the default value is zero, that is, 0L.
For type float, the default value is positive zero, that is, 0.0f.
For type double, the default value is positive zero, that is, 0.0d.
For type char, the default value is the null character, that is,
'\u0000'.
For type boolean, the default value is false.
For all reference types (§4.3), the default value is null.
Each method parameter (§8.4.1) is initialized to the corresponding
argument value provided by the invoker of the method (§15.12).
Each constructor parameter (§8.8.1) is initialized to the
corresponding argument value provided by a class instance creation
expression (§15.9) or explicit constructor invocation (§8.8.7).
An exception parameter (§14.20) is initialized to the thrown object
representing the exception (§11.3, §14.18).
A local variable (§14.4, §14.14) must be explicitly given a value
before it is used, by either initialization (§14.4) or assignment
(§15.26), in a way that can be verified using the rules for definite
assignment (§16 (Definite Assignment)).
So if your field is not being initialized anywhere before it is being used, the initial (or default) value would be null for object/reference types, false for primitive boolean type, or 0 for any other primitive types (0 for char is null character).
If the field is initialized, then we need to look at the order.
private class A {
protected int a = 2;
public A() {
System.out.println("Printing from constructor of A");
printValues();
System.out.println();
}
public void printValues() {
System.out.println("a = " + a);
}
}
private class B extends A {
private int b = 3;
private int c = initC();
public B() {
super();
System.out.println("Printing from constructor of B");
printValues();
System.out.println();
}
#Override
public void printValues() {
super.printValues(); // Call parent implementation
System.out.println("b = " + b);
System.out.println("c = " + c);
}
private int initC() {
System.out.println("Printing from initC()");
printValues();
System.out.println();
return 4;
}
public static void main(String[] args) {
new B();
}
}
This generates:
Printing from constructor of A
a = 2
b = 0
c = 0
Printing from initC()
a = 2
b = 3
c = 0
Printing from constructor of B
a = 2
b = 3
c = 4
In the constructor of A (which is the parent class), a (which belongs to A) is already initialized with 2. The other 2 fields remains un-initialized, returning values specified by JLS 4.12.5.
Then the constructor of A finishes and returns back to the constructor of B (the child class). You would have expected it to go to the B constructor part, but something else happened before that - initC() is being called. At this point, we can see that b has also been initialized, but c hasn't been initialized because initC() is supposed to return the value to initialize c.
Lastly, we see all the 3 fields being initialized.
So this is the order:
Most super class' fields are initialized first.
When returning from super class' constructor, the child class initializes its own fields.
Constructor continues to execute, which allows you to use the initialized values.
So initializing inline at field declaration allows you to be sure that the field has the value when you use it even at constructor, while initializing at constructor could only ensure the value is initialized after it exits the constructor (child class can be sure that it is initialized too).
When instance variables are getting a default value? In the constructor or before the constructor?
Before the constructor. If they got their default value after the constructor, then there would be no point setting them to a different value inside the constructor.
Do constructor have to be called to initialize the instance variables, or the default values are assigned even before the constructor call?
It doesn't matter, the constructor is always called when you make a new instance. If you write a subclass that doesn't explicitly call its superclass's constructor, then the superclass's no-args constructor will be automatically called.
For instance, this:
class B extends A {
public B() {}
}
is equivalent to this:
class B extends A {
public B() {
super();
}
}
If you don't call the superclass constructor explicitly, then your superclass's no-args constructor will be called. If no such constructor exists, then your code will not compile.
A constructor is always called.
I have a code-snippet, and I should determine what line I should un-comment so it will compile.
Question: Why only lines 9,13 and 10,14 works? Why wont 9,14 work for example? I'm a bit confused. help is highly appreciated! (Btw, the options are only un-commenting two lines of code)
1. // Question 3.1
2. class Car {
3. private Car() { }
4. protected Car(int x) { }
5. }
6. public class MG extends Car {
7. // MG(int x) { }
8. // MG(int x) { super(); }
9. // MG(int x) { super(x); }
10. // private MG(int x) { super(x); }
11. // MG() { }
12. // MG() { this(); }
13. // MG() { this(6); }
14. // MG() { super(7); }
15. public static void main(String[] args) {
16. new MG(7);
17. new MG();
18. } }
I believe the lack of understand comes from not enough familiarity of private constructor and protected access modifier, so I'm reading on that and I will also continue trying figuring it out.
Edit: Well I almost got it now, first of all line 8 cant be called so options with 8 and 11-14 are gone. line 7 - why can't it be called for e.g. with line 11? I believe MG(){} will be called but first the private car() has to be called, error. with line 12 not possible, because than I need line 11, with line 13 no idea why, with line 14 no idea why..
I wrote it on Ideone, because i was pretty sure that line 9 and 14 should work and they do!
Check it here (code)
The only important thing to remember in this example is, that if you do not invoke parent constructor, Java will invoke it in that manner "super()". Since your parent class non-parameter constructor is private, it won't compile.
That's why lines 7,8,11 are plain wrong.
Inheritance
Subclass by default get the access of all parent class methods, variables, constructor.
When you are going to create object of child class then (jvm calls zero parameter constructor implicitly)first parent class constructor executed and then child class constructor.
In your case you are calling super class constructor explicitly.
Use print statement in constructor you will get clear idea ...
First of all Few things to notice:
First get some idea about access modifiers:
About private constructor:
prevent subclassing (extending). If you make only a private constructor(only have one constructor), no class can extend your class, because it can't call the super() constructor. read more
And little bit about constructor:
Constructors are never inherited - they are specific to the class in
which they are defined.
If no constructor implemented, default constructor will added by the
compiler implicitly.
In subclasses did not call the super() compiler automatically add those to all the constructors.
When a new object that is a subclass is constructed, the constructor
for the superclass is always called first.
Constructor invocation maybe implicit or explicit.
explicit call to a constructor of superclass: super() - has to be the first statement in the subclass constructor.
Without any constructor in MG:
In this line public class MG extends Car { eclipse show error:
Implicit super constructor Car() is not visible for default
constructor. Must define an explicit constructor.
Because of inheritance you need to pass values to parent class constructor.
And for this new MG(7);:
The constructor MG(int) is undefined
Because you donot have any parameterized constructor in MG class.
UPDATE:
You said in your question you only want to know about line number 7, 11, 12, 13 and 14. But I will answer for all the lines. Then others who looking for answer also can understand
If you uncomment line number 7:
When we create an object of a child class always the constructor of the parent get completed and the constructor of the child runs later.
When you run the program, First in the main method new MG(7); object looking for matching constructor in the MG, which is MG(int x) {}. Inside this has super() which is compiler added one. Then compiler look for default constructor in parent class, It cannot find since default constructor is private.
To fix this: MG(int x) {super(x);}
If you uncomment line number 8:
When you run the program, First in the main method new MG(7); object looking for matching constructor in the MG, which is found.
MG(int x) {super()}
If you added super() or not compiler will add this. There is no different between these two:
MG(int x) {}
MG(int x) {super()}
If you uncomment line number 9:
This line is fine(no errors). First compiler looking for constructor(MG(int x) { super(x); } for object(new MG(7);). Then inside the constructor have called super(x) which is have one argument and it is match with the parent class constructor. As I mentioned before, parent class constructor execute first, Then child class constructor execute.
If you uncomment line number 10:
private MG(int x) { super(x); }
Access modifier is not affected because this class is a subclass and it is not a parent class for any class. And we can create object from calling private constructor. read more about private constructor.
If you uncomment line number 11:
MG() { }
It is match with the new MG(); object. Compiler have added super() but no matching constructor found in the parent class.
If you uncomment line number 12:
MG() { this(); }
First, lets look at what is this():
this can be used inside the Method or constructor of Class.
this works as a reference to the current Object whose Method or
constructor is being invoked.
The this keyword can be used to refer to any member of the current
object from within an instance Method or a constructor.
this() keyword can be used inside the constructor to call another
overloaded constructor in the same Class.
This is also called the Explicit Constructor Invocation.
And this() and super() both cannot use in one constructor.
So this line is unnecessary because you don't have any other MG() constructors. learn more about this.
If you uncomment line number 13:
MG() { this(6); }
This is also unnecessary or cannot be called unless you have another MG() constructor. If you do like this:
MG(){
this(6);
}
MG(int x){
super(x);
}
What happen here is when you run the program new MG(); object find the default constructor and in it call the parameterized constructor(MG(int x){}). Then in the this constructor take the value and send it to the parent class.
If you uncomment line number 14:
MG() { super(7); }
new MG(); is matched with the costructor and in it you have passed value 7 to the parent class parameterized constructor.
Done.
I have this simple piece of code.
abstract class X {
X() {
read();
}
private void read() {
Object obj = new Object();
readValue(obj);
}
protected abstract void readValue(Object obj);
}
class Y extends X {
Object obj = null;
Y() {
super();
}
#Override
protected void readValue(Object obj) {
this.obj = obj;
}
void printer() {
System.out.println("Object = " + obj);
}
}
class Runner {
public static void main(String[] args) {
Y y = new Y();
y.printer();
}
}
When I run the above code, the object gets printed as null. (I get "Object = null")
Surprisingly, in class Y when I remove null declaration
Object obj;
The actual value of the object is printed.
Something like ("Object = java.lang.Object#3cd1a2f1")
Why is such a behavior observed? What is 'this' pointing to? Any object is initialized by null if we just declare it, then why such an aberrant behavior?
The reason the obj field is null is due to the sequence of steps that occur in the constructor call of Y:
The constructor of Y calls the super constructor which eventually calls readValue of the concrete class Y, therefore assigning a non-null value to the obj field.
After the super constructor finishes, the instance field obj is initialized to null due to the variable initializer:
Object obj = null;
When you remove the null initializer, it becomes a simple field declaration with no instance initialization to be performed in step 2.
The apt solution is not to remove the null initializer, but to re-design the whole class hierarchy. For example, since the purpose of readValue seems to just be a setter for a variable, then you don't need to make it override an abstract method in the parent class. Just set it as a separate method and call it after the constructor of Y completes.
This illustrates the dangers of calling an inherited method in a subclass from a superclass constructor. The main danger is that initializers for variables in a subclass run after the superclass constructor completes.
Here is what happens.
An object of y is created.
The superclass constructor X() is called, which calls read().
The read method creates a new Object and passes it to readValue, which is implemented in Y.
The readValue method in Y sets obj to the new object.
The superclass constructor X() completes, and initializers run now in Y, setting obj to null.
The printer method prints "Object = null".
If you remove the declaration of obj in Y, then there is no initializer to run, and the obj variable retains its value.
The JLS, Section 12.5, states:
[A]ll the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.12.5).
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
(emphasis mine)
and
Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized.
The object is null because The superclass constructor runs before the subclass constructor,hence it would only be natural that the statement Object obj = null; is executed after calling super class constructor.
The assignment of Object obj = null; is inlined into the constructor during compile time. This are only accessible in existing instance,
and instance does not exist yet when you are in constructor (it is still under construction).
You can achieve object value(Object = java.lang.Object#3cd1a2f1) by declaringobject object as static.
static Object obj = null;
Generally though, it's bad practice to call overriden methods from a constructor in real time.
I'm getting confused about when the instance initialization block should run.
According to Kathy Sierra's book:
Instance init blocks run every time a class instance is created
So, consider having two classes: a parent and a child, according to this question and java's documentation:
instantiating a subclass object creates only 1 object of the subclass
type, but invokes the constructors of all of its superclasses.
According to the above:
why does the instance initialization block located in superclasses gets called every time an object of the subclass is instantiated? it isn't like that a new object of the superclass is instantiated.
After compilation instance init blocks become part of constructors. javac simply adds the init block to each constructor, that is this:
public class Test1 {
int x;
int y;
{
x = 1;
}
Test1() {
y = 1;
}
}
Is equivalent to this:
public class Test1 {
int x;
int y;
Test1() {
x = 1;
y = 1;
}
}
So the init block runs when constructor runs.
it isn't like that a new object of the superclass is instantiated.
Actually, it is like that.
Every instance of a subclass implicitly contains an instance of its superclass.
A superclass constructor is always invoked as the first step in any constructor (and that in turn runs any instance initializer blocks for the superclass)
Though it was a old post I came across this concept thought worth sharing it
Since we are talking about instance block here is how instance code flow executes in parent child relation class
// Child extends Parent
If we create a object for Child
1) Identification of instance members of the class from parent to child
2) execution of instance variable assignments and instance blocks only on parent class
3)execution of parent constructor
4)execution of instance variable assignments and instance blocks only on Child class
5)Execution of child constructor
Because there is always an implicit super() call(if not done explicitly) to the parent's constructor in the constructor of the child.
In the following example:
class Base {
int x=10;
Base() {
show();
}
void show() {
System.out.print ("Base Show " +x + " ");
}
}
class Child extends Base {
int x=20;
Child() {
show();
}
void show() {
System.out.print("Child Show " + x +" ") ;
}
public static void main( String s[ ] ) {
Base obj = new Child();
}
}
Why is the output as shown below
Child Show 0 Child Show 20
I thought constructors can only access instance members once its super constructors have completed.
I think what is happening here is that the super constructor is calling the child's show() method because this method was overridden in Child. as it has been overridden but why is the value of x 0 and why is it able to access this method before the super constructor has completed?
I think what is happening here is that the super constructor is calling the child's show() method because this method was overriden in Child.
That is correct
but why is the value of x 0
because it's not initialized yet (x of Child)
and why is it able to access this method before the super constructor has completed?
That's exactly why in a constructor you should never call a method, which can be overridden (non-final public and protected).
Edit:
The strange thing here is that everything has default/ package-private visibility. This can have some strange effects. See: http://www.cooljeff.co.uk/2009/05/03/the-subtleties-of-overriding-package-private-methods/
I recommend to avoid overriding methods with default visibility if possible (you can prevent this by declaring them final).
You can call overriden methods from constructors, but it's bad and you shouldn't. You illustrated the reason why this is bad: the derived class doesn't get a chance to get initialized, so uninitialized fields will be used - in your example, the default for int x is 0, that's why it's printing 0.
constructor chaining it makes sense to explain exactly what that is. A subclass constructor method's first task is to call its superclass' constructor method. This ensures that the creation of the subclass object starts with the initialization of the classes above it in the inheritance chain.
http://java.about.com/b/2009/02/07/java-term-of-the-week-constructor-chaining.htm
http://javahours.blogspot.com/2008/12/constructor-chain.html
Childs override of the show method is invoked because that's what the Java spec calls for. Here is a great discussion of why you should not do it. The value of x is zero because Child has not finished initializing yet.