WisdomSoft - for your serial experiences.

5.8 Objectクラス

Java のあらゆるクラスは暗黙的に Object クラスを継承しています。すべてのオブジェクトは安全に Object 型に変換でき、Object 型を汎用的な型として利用できます。

5.8.1 原始クラス

抽象クラスやインタフェースを用いることによって、抽象的な型にオブジェクトを変換することが可能になり、同一のコードで異なる型のオブジェクトにアクセスすることができました。クラスが同じスーパークラスを共有することで、参照型変数をスーパークラスの型でメソッド間のデータ交換ができるようになります。もし、すべてのクラスが同じスーパークラスを共有したとすれば、あらゆる参照型は、そのスーパークラス型に変換することができることになります。

C/C++ 言語には void へのポインタという機能がありました。これは、あらゆるポインタ型を代入することができる汎用的な型です。Java 言語にはこのような型は存在しません。そこで、どのような参照型も変換可能な汎用型を実現するために、すべてのクラスが同じスーパークラスを共有するという方法が用いられています。それが Object クラスです。

Object クラスは、暗黙的にあらゆるクラスが継承しているスーパークラスです。クラスの宣言文に extends が指定されている場合は、指定したクラス型を継承しますが、extends が省略されている場合は、自動的に Object クラスを継承することになるのです。つまり、Java において直接のスーパークラスを持たないのは Object クラスだけであり、そのほかのクラスは明示的にクラスを継承しない場合、暗黙的に Object クラスの直接のサブクラスとなるのです。もちろん、明示的に extends を記述し Object を継承してもかまいません。

Object クラスが提供するメンバは、仮想マシンがオブジェクトを制御するために必要なメソッドや、オブジェクトが最小限公開するべき情報などを提供するメソッドなどが宣言されています。開発者は、Object クラスのメソッドをオーバーライドすることができることに注目してください。

すべてのクラス型変数は、最終的に Object 型までワイドニング変換できることが保証されています。実体のデータ型には興味がなく、単純にインスタンスへの参照を取得したい場合は Object 型として受け渡しすると良いでしょう。例えば、System.out.println() メソッドはプリミティブ型だけではなく、どのような参照型オブジェクトも渡すことができました。これは println() メソッドが Object 型として引数を受け取っているからです。

表1 Object クラスのメンバ
コンストラクタ 解説
public Object() オブジェクトを作成します。
メソッド
public final Class getClass() オブジェクトの実行時クラスを返します。
public int hashCode() オブジェクトのハッシュコード値を返します。
public boolean equals(Object obj) このオブジェクトと他のオブジェクトが等しいかどうかを示します。
protected Object clone()
throws CloneNotSupportedException
このオブジェクトのコピーを作成して返します。
public String toString() オブジェクトの文字列表現を返します。
public final void notify() このオブジェクトのモニターで待機中のスレッドを 1 つ再開します。
public final void notifyAll() このオブジェクトのモニターで待機中のすべてのスレッドを再開します。
public final void wait(long timeout)
throws InterruptedException
別のスレッドがこのオブジェクトの notify() メソッドまたは notifyAll() メソッドを呼び出すか、指定された時間が経過するまで、現在のスレッドを待機させます。
public final void wait(long timeout, int nanos)
throws InterruptedException
他のスレッドがこのオブジェクトの notify() メソッドまたは notifyAll() メソッドを呼び出すか、他のスレッドが現在のスレッドに割り込みをかけたり、指定された量の実時間が経過するまで、現在のスレッドを待機させます。
public final void wait()
throws InterruptedException
他のスレッドがこのオブジェクトの notify() メソッドまたは notifyAll() メソッドを呼び出すまで、現在のスレッドを待機させます。
protected void finalize()
throws Throwable
このオブジェクトへの参照はもうないとガベージコレクションによって判断されたときに、ガベージコレクタによって呼び出されます。

表1に Object クラスで宣言されているメンバを列挙します。今は、すべてのメンバについて意味を理解する必要はありません。開発者にとって特に、重要なのはオーバーライド可能なメソッドです。実は、println() メソッドの引数に参照型を指定すると、メソッドは toString() メソッドを呼び出して取得した文字列を画面に表示しているのです。これが println() メソッドのカラクリです。

クラス開発者は toString() メソッドをオーバーライドすることで、オブジェクトの文字列表現をより具体的に示すことができるようになります。toString() メソッドをオーバーライドし、返す値を変化させれば、当然 println() メソッドにオブジェクトを渡した時の結果も変化することでしょう。

コード1
class Point {
	public final int x , y;
	public Point(int x , int y) {
		this.x = x;
		this.y = y;
	}
	public String toString() {
		return "X = " + this.x + " : Y = " + this.y;
	}
}

class Test {
	public static void main(String args[]) {
		Point pt = new Point(400 , 300);
		System.out.println(pt);
	}
}
実行結果
>java Test
X = 400 : Y = 300

コード1の Point クラスは、Object クラスの toString() メソッドをオーバーライドしています。println() メソッドにオブジェクトを渡した場合は、toString() メソッドが返した値を画面に表示します。toString() をオーバーライドしない場合はクラス名とハッシュコードが表示されましたが、このプログラムではオーバーライドされているため、Point クラスの toString() メソッドが返した文字列が表示されています。

すべてのクラス型が Object に変換できるという事実は極めて重要です。オブジェクトのリストを管理するクラスなどを設計する場合、あらゆるオブジェクトを管理対称にするために Object 型としてデータを交換するという方法が考えられるからです。