What happens when subclasses don't define a constructor in Java? - java

I have a few cases I wonder about. First, if you have no constructor:
class NoCons { int x; }
When I do new NoCons(), the default constructor gets called. What does it do exactly? Does it set x to 0, or does that happen elsewhere?
What if I have this situation:
class NoCons2 extends NoCons { int y; }
What happens when I call new NoCons2()? Does NoCons's default constructor get called, and then NoCons2's constructor? Do they each set the respective x and y fields to 0?
What about this version:
class Cons2 extends NoCons { int y; public Cons2() {} }
Now I have a constructor, but it doesn't call the super class's constructor. How does x ever get initialized? What if I had this situation:
class Cons { int x; public Cons() {} }
class NoCons2 extends Cons { int y; }
Will the Cons constructor be called?
I could just try all these examples, but I can't tell when a default constructor is run. What's a general way to think about this so that I'll know what happens in future situations?

When a Java class has no constructor explicitly defined a public no-args default constructor is added so:
class Cons { int x; }
is equivalent to:
class Cons { int x; public Cons() {} }
A subclass's constructor that doesn't explicitly define which of its parent's constructor it calls will automatically call the default constructor in the parent class before it does anything else. So assuming:
class A { public A() { System.out.println("A"); } }
then this:
class B extends A { public B() { System.out.println("B"); } }
is exactly equivalent to:
class B extends A { public B() { super(); System.out.println("B"); } }
and the output in both cases will be:
A
B
So when you do:
new NoCons2();
The order is:
NoCons's default constructor called, although this is technically the first part of (2); and then
NoCons2's default constructor called.

You want to refer to the Java Language Specification section 12.5 Creation of New Class Instances to get the official rules of object creation. The relevant section is:
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 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. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
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.
So in your examples, when no constructor is supplied in your class definition, the default one is inserted for you. When you write
new NoCons2();
First the super constructor is called (a call to super() is inserted for you because you don't make the call explicitly).
Instance variables for the class being constructed are initialized.
The rest of the constructor body is executed (nothing in your case).
In your first example, x will be set during the construction of NoCons and y will be set during the construction of NoCons2.
So the exact sequence of events in that example will be something like:
NoCons2 constructor called.
Call to super(), goto 3
NoCons constructor called.
Call to super(), which is an implicit call to Object().
Whatever happens in Object constructor.
x is set to 0.
finish body of NoCons constructor, return control back to NoCons2 constructor.
y is set to 0.
finish body of NoCons2 constructor
NoCons2 object construction complete.

cletus answered the biggest of the questions. The answer to the other is that member variables in Java are initialized to 0, null or false (depending on the type).

Here is essentially what happens when "new" is called:
the memory is allocated (enough to hold all of the data members of the class, and all of the parent classes, and some housekeeping information)
the allocated memory is set to zero (which means 0, 0.0, false, null depending in the type)
the constructor is called for the class that is after "new" is called.
more things happen (coming after the next part)
If you do not provide a constructor the compiler does the following:
creates a no-argument constructor
the created constructor has the same access as the class (so public or package)
super() is called.
So when the constructor of the class after the "new" is called the very first thing it does is call "super()" which calls the parent constructor. This happens all the way up to java.lang.Object.
Before the body of the constructor is run the VM does the following:
the instance variables that are assigned values are given them
then the instance initializer block, if present is run.
The following code shows all of this:
public class Main
{
private Main()
{
}
public static void main(final String[] args)
{
final Foo fooA;
final Foo fooB;
fooA = new Foo(7);
System.out.println("---------------------");
fooB = new Foo(42);
}
}
class Bar
{
protected int valueA = getValue("valueA", 1);
protected int valueB;
static
{
System.out.println("static block for Bar happens only one time");
}
{
System.out.println("instance block for Bar happens one time for each new Bar");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
}
Bar()
{
super(); // compiler adds this - you would not type it in
System.out.println("running Bar()");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
valueB = getValue("valueB", 2);
}
protected static int getValue(final String name, final int val)
{
System.out.println("setting " + name + " to " + val);
return (val);
}
}
class Foo
extends Bar
{
protected int valueC = getValue("valueC", 1);
protected int valueD;
static
{
System.out.println("static block for Foo happens only one time");
}
{
System.out.println("instance block for Foo happens one time for each new Foo");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
}
Foo(final int val)
{
super(); // compiler adds this - you would not type it in
System.out.println("running Foo(int)");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
valueD = getValue("valueD", val);
}
}

Related

Calling Constructor Multiple times

How to call the Constructor multiple times using the same object
class a
{
a(int i)
{
System.out.println(i);
}
public static void main(String args[])
{
a b = new a();
int x = 10;
while( x > 0)
{
//Needed to pass the x value to constructor muliple times
}
}
}
I needed to pass the parameter to that constructor.
Constructor of a class A constructs the objects of class A.
Construction of an object happens only once, and after that you can modify the state of the object using methods (functions).
Also notice if programmer does not write any constructor in his class then the Java compiler puts the constructor for the class (public constructor without any parameters) on its own.
In the case where a constructor has been provided by the programmer, the compiler does not create a default constructor. It assumes, the programmer knows and wants creation of the objects of his/her class as per the signature of the explicit constructor.
Constructor calls are chained. Suppose there exists below class relationship.
Child.java extends Parent.java and Parent.java extends GrandParent.java.
Now if Child child = new Child(); is done, only one object is created and that is of Child.java, but the object also has all of the features of GrandParent first then with the features of the Parent and then the Child.
Hence first constructor of GrandParent.java is called then Parent.java is called and lastly the constructor of Child.java is called.
Constructors are special and different from other methods.
The intent of constructors is to create the object, so each time you use the new operator, the constructor is called and a new object is created. You can not call the constructor directly. You need the new operator to call it. Even if you see some class defining methods like getInstance(), it still uses the new operator to construct the object and return the created object.
*PS there are ways to create an object without calling constructor (like Serialization) but that is out of context of the discussion here.
Constructors are called only once at the time of the creation of the object.
Can you please be specific about what you want to achieve?
But I think you could try one of the following two things.
Calling the constructor to create a new object and assigning it to the object 'b':
b = new a(1);
Using the setter method:
void setI(int i){
this.i = i;
}
b.setI(1);
int x = 10;
while( x > 0)
{
a b = new a(x);
}

Java abstract class constructor

I'm wondering what is happening here:
I have abstract superclass
public abstract class Superclass {
public Superclass()
{
doSth();
}
public abstract void doSth();
}
And subclass
public class Subclass extends Superclass{
private int x = 10;
public void doSth()
{
System.out.println("Value x="+this.x);
}
}
When I make
Subclass x= new Subclass();
x.doSth();
I get:
Value x=0
Value x=10
I don't know why first I get x=0 (why not x=10 from the start?) and then x=10?
The constructor of the super-class is executed before the isntance initializer expressions of the sub-class, which is why x still has the default value of 0 in the first call to doSth(). The second call x.doSth() takes places after the Subclass instance is fully initialized, so x contains 10.
More details :
When you call the constrcutor of Subclass, first it calls the constructor of Superclass which calls the constructor of Object. Then the body of the Superclass constructor is executed, so doSth() is executed. Only after the Superclass constructor is done, the instance initialization expressions of Subclass (in your case, the assignment x = 10; are evaluated. Before they are evaluated, x still contains the default value - 0, which is the value you see printed by the first call to doSth().

Why is the value of the instance field coming null?

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.

Instance variable, when re-initialised in sub class' initialization block, is overridden like instance method, which it should not

I have just started learning Java.I understand
Unlike instance method, instance variable can not be overridden, and are not dynamically picked by JVM at run time when accessed polymorphically.
flow of execution : static block, super constructor, initialization block and then constructor.
But I am stuck at one code, where I have polymorphically invoked a instance variable but its showing overridden value (which it should not show). The instance variable is overridden inside sub class' init block.
package package1;
public class Other {
public static void main(String [] args){
Parent referToChild = new Child();
Parent referToChildTwo = new ChildTwo();
System.out.println("age as referred by referToChild reference variable is:" + referToChild.age);// prints 35 (doubt 1)
System.out.println("age as referred by referToChildTwo reference variable is:" + referToChildTwo.age);// prints 50 (doubt 2)
System.out.println("money as referred by Other reference variable is:" + referToChild.money);
//System.out.println("Other reference variable is:" + othObj.age);
}
}
class Child extends Parent{
// init block
{
age = 35;
}
}
class ChildTwo extends Parent{
public int age;
{
age = 40;
}
}
class Parent{
public int age = 50;
public int money = 100;
}
The answer I get is:
35
50
100
so my doubts are:
doubt 1 :Why is it showing "35", it should display super class' variable's value which is 50.
doubt 2 : When it is displaying sub class' variable's value for last case, then why not for this case.
Why is it showing "35", it should display super class' variable's value which is 50.
The initializer block of subclass Child executes after the variable age is initialized in the Parent class. Therefore, age is first initialized to 50, then to 35.
This is explained in great detail in the Java Language Specification Section 12.5 on Creation of New Class Instances, with the relevant part in bold:
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.
As for the second question, referToChildTwo is declared of type Parent, while its actual type is ChildTwo. A ChildTwo instance has two age fields, the one defined in ChildTwo and the other one inherited from Parent.
When you write the expression referToChildTwo.age, the field inherited in Parent will be evaluated. To evaluate the one defined in the subclass, you would need to cast the variable, i.e. ((ChildTwo)referToChildTwo).age.
It cannot be overridden, but it is inherited by child classes as long as it wasn't private in the parent. And they can access it, including both reading and writing it.
Overriding is creating a new member which is part of the current class, which has the same definition of the member of the parent class, and for that member to be accessed when you use the object polymorphically.
For example:
class Parent {
public int age = 50;
}
class Child {
public int age = 80;
}
Here we defined a new member, age, which is separate from the parent's age. If you access it from inside Child using this.age, you'll get 80. If you access the parent's age using super.age, you'll get 50.
But this is not overriding, because if you use the object polymorphically, it will access the parent's age:
Child childObj = new Child();
Parent parentObj = childObj;
System.out.println( childObj.age ); // Will print 80
System.out.println( parentObj.age ); // Will print 50
This is despite the fact that they are both the same object. That's because the child hides the field rather than override it.
Simply assigning a value in a field inherited from the parent is not overriding. It's part of what inheritance is all about.

java constructor order

This java program is easy and full of comment,so you can understand it fast.however,why in construct staff[1],the program first go to the statement:
this("Employee #" + nextId, s);
then go to the object initialization block,and then go back to the statement,how confusion.why not it first use the object initialization block
import java.util.*;
public class ConstructorTest
{
public static void main(String[] args)
{
// fill the staff array with three Employee objects
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry", 40000);
staff[1] = new Employee(60000);
staff[2] = new Employee();
// print out information about all Employee objects
for (Employee e : staff)
System.out.println("name=" + e.getName()
+ ",id=" + e.getId()
+ ",salary=" + e.getSalary());
}
}
class Employee
{
// three overloaded constructors
public Employee(String n, double s)
{
name = n;
salary = s;
}
public Employee(double s)
{
// calls the Employee(String, double) constructor
this("Employee #" + nextId, s);
}
// the default constructor
public Employee()
{
// name initialized to ""--see below
// salary not explicitly set--initialized to 0
// id initialized in initialization block
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public int getId()
{
return id;
}
private static int nextId;
private int id;
private String name = ""; // instance field initialization
private double salary;
// static initialization block
static
{
Random generator = new Random();
// set nextId to a random number between 0 and 9999
nextId = generator.nextInt(10000);
}
// object initialization block
{
id = nextId;
nextId++;
}
}
Because this("Employee #" + nextId, s); includes an implicit call to the superclass constructor, which of course must be executed before the initializer block of the subclass.
Using instance initializers is generally a bad idea as they are not well known, cannot do anything more than constructors, and mixing both leads to confusion.
This follows the order specified in section 8.8.7.1 of the JLS:
(Final two bullets)
Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created. The evaluation of an explicit constructor invocation proceeds as follows:
First, if the constructor invocation statement is a superclass constructor invocation,
(Snipped because it's not in our case)
Next, the constructor is invoked.
Finally, if the constructor invocation statement is a superclass constructor invocation and the constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. (Snip) An alternate constructor invocation does not perform this additional implicit action.
So the instance initializer is executed immediately after the superconstructor is called - which is (implicitly) from public Employee(String n, double s). This should happen before the body of that two-parameter constructor is executed.
Not sure what the actual question is, it's a bit confusing. The order of initialization (static, object, constructor) is predefined and has nothing to do with in which order they appear in the code. As for the general style, I generally discourage using object initialization blocks. It's a very common source of errors, it makes exception-handling more complex and it's hard to debug. In addition, it's not a very common pattern so developers tend to miss looking for it when analyzing bugs.
The Java compiler must ensure that the code in the object initialization block is called from each constructor. For most constructors, it does this by inserting the code into the constructor right after the implicit or explicit call to super(). For compilers that start with this(), however, first of all there is no implicit call to super() -- the other constructor handles that. Secondly, in such a constructor the object initializer block can't be inserted at all, since the code will be picked up when the second constructor is called. Therefore the this() call is the very first thing that happens.

Categories