コンストラクタ

コンストラクタとはクラスのインスタンスが生成される時に呼び出される特殊なメソッドでした。
JVMはコンストラクタが呼び出されるタイミングでヒープ領域にインスタンスを生成します。
この時、メソッド領域にあるクラス情報からどんなインスタンス変数があるかを読み込み、メモリに展開します。

メソッドの引数で定義された変数

メソッドで宣言された変数(ローカル変数)は全てスタック領域に確保されていました。
メソッドの引数として宣言された変数も同様にスタック領域に確保されますが、初期値として呼び出し元で引数に指定した値が代入されます。

インスタンス変数

これに対し、クラスに定義されたインスタンス変数(メンバ変数)はヒープ領域に確保されます。
インスタンス変数はインスタンス毎に別の値として管理する必要があるからです。
したがって、ヒープ領域に確保されたインスタンスインスタンス変数の集合とも言え、ヒープ領域に確保されるメモリのサイズ、インスタンス変数の数と型に依存します。

実際にはインスタンス変数のサイズ合計に幾つかの情報が加えられたサイズとなりますが、大雑把な消費メモリの試算は、メンバ変数のサイズ合計×インスタンス数で図れます。
例えば、インスタンス変数に10個のint型を持っているとすればint型は32bit(4byte)なので40byte/インスタンスとなります。
1回に1,000個のインスタンスが生成されることが予想されるならば、40,000byte(≒約40kB)が消費メモリと考えて問題ありません。
大量にデータを作成しなければならない場合は考慮すべきでしょう。

参照型のインスタンス変数

インスタンス変数にはプリミティブ型だけではなく、参照型変数も定義することができます。
この参照型のインスタンス変数はインスタンス内に確保され、他のプリミティブ型の変数と同じように扱われます。
プリミティブ型のインスタンス変数と異なるのは、含まれる値が他のインスタンスを参照しているということです。

このようにインスタンス変数(ヒープ領域)で他のインスタンスを参照している事を弱参照(weak reference)と呼ばれます。
これに対しローカル変数(スタック領域)でヒープ領域のインスタンスを参照している事は(strong reference)と呼ばれます。
GCの対象になるかどうかは弱参照も強参照もなくなった時です。
一般的に強参照はコードを追うことで開放されGCの対象となるタイミングが解り易いのですが、弱参照は追いにくい場合があるためメモリリークの原因となることがあります。

尚、参照型変数は32bit(4byte)のサイズを持っているようです(定義されているわけではないですし、環境によっては違うかもしれませんので目安と考えてください)。

引数を持つコンストラク

コンストラクタにはメソッドと同じように引数を定義することができます。
主に各インスタンス変数の初期値などを引数として定義し、インスタンス変数の初期値を設定する為に使われます。

public class Foo
{
    private int num = 0;
    public Foo()
    {
    }
    public Foo(int value)
    {
        // 初期値設定
        num = value;
    }
}

また、コンストラクタは複数定義することもできます。
これはコンストラクタのオーバーロードです。

this

thisは自分自身を参照する特別な予約語ですが、コンストラクタでは定義されている他のコンストラクタを実行する為に使用することができます。
一般的にコンストラクタを複数定義する場合には、メソッドのオーバーロードと同じように似た処理が多くなります。
そこで、最も複雑な処理を行うコンストラクタに処理をまとめておき、他のコンストラクタからはthisを使用して呼び出すと効率よく見通しもよいコードとなります。

public class Foo
{
    private int num = 0;
    public Foo()
    {
        // 引数ありのコンストラクタを実行
        this(0);
    }
    public Foo(int value)
    {
        // 初期値設定
        num = value;
    }
}

このようにthisをコンストラクタの実行に使う場合は、コンストラクタをthisという名のメソッドのように使用します。
ただし、thisはコンストラクタの記述の先頭に書く必要があります(よって、2回以上呼び出すこともできません)。

デフォルトのコンストラク

コンストラクタはインスタンスの生成の時に実行されるものですから、クラスに1つは必ず必要となります。
しかし、コンストラクタを1つも記述しなかった場合、コンパイラは自動的にデフォルトのコンストラクタを定義します。
デフォルトのコンストラクタとは引数を持たず、publicで初期化以外の処理を一切行わないシンプルなコンストラクタです。

public class Foo
{
    // コンストラクタは省略できるが次のように記述されているとみなせる
//    public Foo()
//    {
//    }
}

このデフォルトのコンストラクタは他の引数を持つコンストラクタを定義すると自動的には定義されないことに注意してください。

インスタンス変数の初期値

インスタンス変数には次のように定義に初期値を与えておくことができます。

public class Foo
{
    private int num = 0;
}

しかし、宣言と共に初期化を省略し宣言のみで記述することもできます。

public class Foo
{
    private int num;
}

この時、省略されているのであり実は0で初期化されています。
どのような値で初期化されるかは変数の型によって異なりますが、数値型であれば0、boolean型であればfalseとなります。
参照型変数の場合、参照のゼロにあたるnullが初期値となります。

null

参照型変数がインスタンスを参照していない場合、null参照であると呼びます。
このnull(ヌル)とはインスタンスが存在しない状態を表す特殊なリテラル(定数)です。
nullはnull型という特殊な型(≠クラス)の唯一のリテラル(定数)であり、インスタンスではありません。
nullはどのような参照型変数にも代入することができる特殊なリテラルです。

継承とコンストラク

Javaのクラスは継承による階層構造を持っていました。
この構造はインスタンスの生成時、どのような形でメモリに反映されるのでしょうか?

インスタンスの生成時にはスーパークラスから順番に初期化されます。
ルートクラスと言えるクラスはObjectクラスでしたので、どのようなクラスでも必ず最初はObjectクラスの初期化が行われていると言えます。
その後はサブクラスを順次初期化して行き、newしたクラスが初期化されたときにインスタンスが生成されることになります。
各クラスに定義されたコンストラクタはこのように階層化されて実行される為、コンストラクタを独自に定義する場合は充分に気をつけなければなりません。

super

クラスにコンストラクタを明示的に定義しない場合、デフォルト(引数無し)のコンストラクタが自動的に定義されました。
実はこのデフォルトのコンストラクタこそが、自然に階層化されたクラスの初期化を行うことを手助けしています。

サブクラスで明示的にスーパークラスのコンストラクタを実行したい場合はsuperキーワードを用います。

public class Bar extends Foo
{
    public Bar()
    {
        super();
    }
}

superはthisと同様にコンストラクタの先頭に記述しなければなりません。
また、thisと併用することも出来ません。
thisを用いた場合は、スーパークラスのコンストラクタの呼び出しを他のコンストラクタに実行させているからです。
このsuper()は今まで記述してこなかったことから解るように、省略することができます。
this文が存在しなかった場合はスーパークラスのデフォルトコンストラクタが実行されると定められているのです。

デフォルトのコンストラクタがない場合

引数のあるコンストラクタを明示的にスーパークラスに定義した場合、デフォルトのコンストラクタは明示的に記述しない限りは存在しません。

public class Foo
{
    public Foo(int num)
    {
    }
}

したがって、次のようにサブクラスを定義するとコンパイルエラーとなります。

public class Bar extends Foo
{
}

何故ならば、Barにはコンストラクタが明示的に記述されていない為、デフォルトのコンストラクタが定義されますが、その中で自動的に呼び出されるスーパークラスのコンストラクタはデフォルトのコンストラクタだからです。
スーパークラスの引数のあるコンストラクタを実行する方法はthisと同様に引数を指定することです。

public class Bar extends Foo
{
    public Bar(int num)
    {
        super(num);
    }
}

デフォルトのコンストラクタを定義したいならば次のように記述できます。

    public Bar()
    {
        super(0);
    }

もしくはthisを用いて次のように書くこともできるでしょう。

    public Bar()
    {
        this(0);
    }

このような仕組みを持つ為、コンストラクタはメソッドのような性質を持ちますが、特殊なメソッドと位置づけられオーバーライドができないようになっています。

継承されたインスタンス変数のメモリ管理

それでは最後にインスタンス変数が継承の中でメモリ上はどのように管理されているかを図に表します。

このようにヒープの中では各クラスのデータも階層構造を持っています。
従って、各クラスで定義されたインスタンス変数は継承されたクラスからアクセスできるかどうかの違いはありますが、お互いに独立した変数であることが解るでしょう。
したがって、privateのインスタンス変数はお互いに干渉することはないこと、同じ名前のインスタンス変数を定義してもオーバーライドにはならないことが解ると思います(通常はprivateでないインスタンス変数と同じ名前のインスタンス変数をサブクラスで定義することは出来ますがバグとみなされます)。