tags:

views:

131

answers:

4

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?

+10  A: 

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:

  1. NoCons's default constructor called, although this is technically the first part of (2); and then
  2. NoCons2's default constructor called.
cletus
A: 

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).

Kevin Day
+1  A: 

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:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
  2. 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.
  3. 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.
  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.)
  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.

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();
  1. First the super constructor is called (a call to super() is inserted for you because you don't make the call explicitly).
  2. Instance variables for the class being constructed are initialized.
  3. 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:

  1. NoCons2 constructor called.
  2. Call to super(), goto 3
  3. NoCons constructor called.
  4. Call to super(), which is an implicit call to Object().
  5. Whatever happens in Object constructor.
  6. x is set to 0.
  7. finish body of NoCons constructor, return control back to NoCons2 constructor.
  8. y is set to 0.
  9. finish body of NoCons2 constructor
  10. NoCons2 object construction complete.
Bill the Lizard
A: 

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);
    }
}
TofuBeer