クラスの継承とObjectクラスの関係

1.5 クラスの継承とObjectクラスの関係

 本章の学習でクラスを拡張する様々な仕組みについてみてきました。クラスの拡張と継承についての関係をさらに詳しくみていきましょう。

1.5.1 クラスの階層について

 これまでのプログラム中で普通に行ってきましたが、複数のサブクラスに1つの同じスーパークラスを継承することもできます。この時のクラス同士の関係は以下の図1.5.1のようになります。

図 1.5.1: 複数のサブクラスで1つのスーパークラスを継承

 また、サブクラスを継承したさらに新しいサブクラスを作成することもできます。新しいサブクラスから見ると最初のサブクラスがスーパークラスになります。新しいサブクラスには、サブクラスのメンバとして大元のスーパークラスのメンバも継承されることになります。関係は以下の図1.5.2になります。

図 1.5.2: サブクラスを拡張

 なお、複数のサブクラスに1つの同じスーパークラスを継承することはできますが、1つのサブクラスに複数のスーパークラスを継承することはできないようになっています。

図 1.5.3: 多重拡張(継承)の禁止

1.5.2 Objectクラスの仕組みを知る

 本章でクラス拡張の仕組みを行う以前では、スーパークラスを特に指定せずにクラスを作成してきました。Javaではクラス作成時にスーパークラスを指定しなかった場合、そのクラスは、Objectクラスをスーパークラスにもつという決まりになっています。これまで目にしてきた、以下の図1.5.4ようなクラスは実はObjectクラスをスーパークラスとしたサブクラスになっていた訳です。

図 1.5.4: クラス作成時のObjectクラスの自動拡張(継承)

 この仕組みによりスーパークラスの指定が無いクラスは全てObjectクラスを継承したクラスとなり、そのクラスを継承したクラスも自動的にメンバ全てを継承することになります。結果Javaの全クラスは必ずObjectクラスのメンバを継承している仕組みになっています。

図 1.5.5: クラスはObjectクラスのメンバを継承

ポイント
  • スーパークラスを指定しないクラスは、自動的にObjectクラスのサブクラスになり、結果としてスーパークラスを継承するとObjectクラスのメンバも継承したことになる

 次項よりObjectクラスとは一体どのようなクラスなのかみていきましょう。

1.5.3 Objectクラスについて

 Objectクラスを簡単に表すと「全てのJavaクラスを形作るためのクラス」となり、全てのクラスが継承しなければいけないクラスとなります。よってスーパークラスの指定が無い場合は、暗黙的にObjectクラスを継承する仕組みになっています。
 ではObjectクラスにはどのようなメンバをもつクラスなのか、以下の表1.5-1を見て下さい。

表 1.5.1

 それほどメンバも多くなく重要な機能を提供するメソッドもありません。あくまでベースとなる基本クラスのため最低限のメンバが用意されているのです。
 では次の項より実際にObjectクラスのメンバをいくつか使ったプログラムを紹介していきいます。

1.5.4 ObjectクラスのtoStringメソッドを利用したプログラム

 ObjectクラスがもつtoStringメソッドを利用して、オブジェクトの文字表現を画面に出力します。さらにオーバーライド機能を利用して任意のオブジェクト文字表現を表示できるようにします。

toStringメソッドの仕組み
 toStringメソッドは「オブジェクトの文字列表現を返す」と定義されています。オブジェクトを指し示すクラス変数を標準出力処理する時に、このメソッドが呼び出されることになっています。または直接toStringメソッドを呼び出しても結果は同じになります。

凡例:オブジェクトの文字表現を出力する
 デフォルトのオブジェクトの文字表現はパッケージ名.クラス名@数値が表示されます。

ソースコード

① ソース・フォルダー      :myproj_basic/src
② パッケージ          :jp.co.f1.basic.ch11
③ 名前             :Computer5

➢ Computer5.java ※ObjectクラスのtoStringメソッドをオーバーライドしていない従来のクラス
package jp.co.f1.basic.ch11;

public class Computer5 {
	private String os;
	private int memory;

	public Computer5(){
		this.os = null;
		this.memory = 0;
		System.out.println("パソコンを作成しました。");
	}
	public void setOsMemory(String os,int memory){
		this.os = os;
		this.memory = memory;
		System.out.println("OSを「" + os + "」にメモリを「" + memory + "MByte」に変更しました。");
	}
	public void show(){
		System.out.println("パソコンのOSは「" + os + "」です。");
		System.out.println("メモリサイズは「" + memory + "MByte」です。");
	}
}

① ソース・フォルダー      :myproj_basic/src
② パッケージ          :jp.co.f1.basic.ch11
③ 名前             :Computer6

➢ Computer6.java ※ObjectクラスのtoStringメソッドをオーバーライドしているクラス
package jp.co.f1.basic.ch11;
public class Computer6 {
	private String os;
	private int memory;

	public Computer6(){
		this.os = null;
		this.memory = 0;
		System.out.println("パソコンを作成しました。");
	}
	public void setOsMemory(String os,int memory){
		this.os = os;
		this.memory = memory;
		System.out.println("OSを「" + os + "」にメモリを「" + memory + "MByte」に変更しました。");
	}
	public void show(){
		System.out.println("パソコンのOSは「" + os + "」です。");
		System.out.println("メモリサイズは「" + memory + "MByte」です。");
	}
	//オーバーライドしたtoStringメソッド
	public String toString(){
		String str = "OS:" + this.os + " " + "Memory:" + this.memory;
		return str;
	}
}

① ソース・フォルダー      :myproj_basic/src
② パッケージ          :jp.co.f1.basic.ch11
③ 名前             :UseToStringMethod
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

➢ UseToStringMethod.java ※mainメソッドを持つ実行クラス
package jp.co.f1.basic.ch11;

public class UseToStringMethod {
	public static void main(String[] args) {
		//Computer5クラスのオブジェクト生成
		Computer5 com1 = new Computer5();
		System.out.println(com1);

		//Computer6クラスのオブジェクト生成
		Computer6 com2 = new Computer6();
		com2.setOsMemory("WindowVista", 2048);
		System.out.println(com2);
	}
}

実行結果

解説

 Computer5クラスは従来の方法でクラス定義を行っています。
 もう1つのComputer6クラスはObjectクラスのメンバであるtoStringクラスをオーバーライドしています。それがComputer6.javaの22~25行目の部分になり、パソコン情報を戻り値に設定するようにしています。
   22:public String toString(){
   23: String str = "OS:" + this.os + " " + "Memory:" + this.memory;
   24: return str;
   25:}

 UseToStringMethodクラスの6行目で、toStringメソッドのオーバーライドを行っていないComputer5クラスのオブジェクト生成を行っています。そして7行目でクラス変数com1の標準出力処理を行っています。
   6:Computer5 com1 = new Computer5();
   7:System.out.println(com1);

 10行目ではtoStringメソッドをオーバーライドしているComputer6クラスのオブジェクト生成を行っています。11行目でsetOsMemoryメソッドを利用して情報の設定、12行目でクラス変数com2の標準出力処理を行っています。
   10:Computer6 com2 = new Computer6();
   11:com2.setOsMemory("WindowsVista", 2048);
   12:System.out.println(com2);

 実行結果を見ても分かるように、オーバーライドしていないComputer5クラスのオブジェクト文字列表現は「パッケージ名.クラス名@数値」となり、オーバーライドしているComputer6クラスは「パソコン情報」が正しく表示されているのが確認できます。

 今回のプログラムのように、クラス変数の標準出力(toStringメソッドを呼び出し)を行うとオブジェクトの文字列表現した情報を表示することができます。実際出力されるものは余り意味の無い文字列表現のため、頻繁に出力処理を行う場合にはtoStringメソッドをオーバーライドして任意の値を出すようにしておけば大変便利です。

ポイント
  • スーパークラスと同じ定義のメソッドを持つサブクラスから、そのメソッドを呼び出すとサブクラスのメソッドが呼び出される。

1.5.5 Objectクラスのequalsメソッドを利用したプログラム

 Objectクラスのequalsメソッドを利用して、オブジェクトが同じものかを比較して確認します。

equalsメソッドの仕組み
 このequalsメソッドはStringクラスでも出てきたのは覚えているでしょうか。StringクラスではこのObjectクラスのequalsメソッドがオーバーライドされています。その結果、文字列の比較が正しく行われるようになっています。ではObjectクラスはのequalsメソッドはどのような機能なのかというと、クラス変数が指し示すオブジェクトが同じものかどうかを判定し結果をboolean型で返します。

 ※Objectクラスのequalsメソッドは、オブジェクトの場所情報が同じなのかを比較します。

➢ Computer5.java ※ObjectクラスのtoStringメソッドをオーバーライドしていない従来のクラス
 1.5.4で作成したクラスを利用します。

① ソース・フォルダー      :myproj_basic/src
② パッケージ          :jp.co.f1.basic.ch11
③ 名前             :UseEqualsMethod
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

➢ UseEqualsMethod.java

package jp.co.f1.basic.ch11;

public class UseEqualsMethod {
	public static void main(String[] args) {
		Computer5 com1 = new Computer5();
		Computer5 com2 = new Computer5();
		Computer5 com3 = com1;

		boolean check1 = com1.equals(com2);
		boolean check2 = com1.equals(com3);

		System.out.println("com1とcom2の比較結果は" + check1 + "です。");
		System.out.println("com1とcom3の比較結果は" + check2 + "です。");
	}
}

実行結果

解説

 5行目でComputer5クラスのオブジェクトを新しく1つ作成しています。
 6行目でもComputer5クラスのオブジェクトを新しく1つ作成しています。
 7行目はcom3の中に5行目で生成したオブジェクトの場所情報を代入しています。
   5:Computer5 com1 = new Computer5();
   6:Computer5 com2 = new Computer5();
   7:Computer5 com3 = com1;

 9行目でequalsメソッドを利用してcom1とcom2が同じオブジェクトの場所情報を保持しているか比較しています。その結果を変数check1に受け取ります。
 10行目も9行目と同じようにequalsメソッドを利用しています。ここでは比較対象がcom1とcom3に変わっています。そして結果を変数check2に受け取ります。
   9:boolean check1 = com1.equals(com2);
   10:boolean check2 = com1.equals(com3);

 12行目ではcom1とcom2の比較結果を画面に表示しています。
 13行目ではcom1とcom3の比較結果を画面に表示しています。
   12:System.out.println("com1とcom2の比較結果は" + check1 + "です。");
   13:System.out.println("com1とcom3の比較結果は" + check2 + "です。");

 実行結果を見て分かるように、com1とcom2は違うオブジェクトの場所情報を保持している為結果はfalseとなり、逆にcom3はcom1を代入して同じオブジェクトの場所情報を保持している為結果はtrueとなります。

ポイント
  • Objectクラスのequalsメソッドを利用すると、比較したものが同じオブジェクトなのか調べることができる。

1.5.6 ObjectクラスのgetClassメソッドを利用するプログラム

 ObjectクラスのgetClassメソッドを利用して、オブジェクトがどのクラスに所属しているのか確認します。

getClassメソッドの仕組み
 このgetClassメソッドを利用すると、オブジェクトが属するクラスの情報を返してくれます。その際の戻り値はClass型のオブジェクトになりますが、そのまま標準出力することで「class パッケージ名.クラス名」と表示してくれます。

ソースコード
➢ Computer2.java ※スーパークラス
 1.3.7で作成したクラスを利用します。

➢ NotePc6.java ※サブクラス
 1.4.2で作成したクラスを利用します。

① ソース・フォルダー      :myproj_basic/src
② パッケージ          :jp.co.f1.basic.ch11
③ 名前             :UseGetClassMethod
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

➢ UseGetClassMethod.java
package jp.co.f1.basic.ch11;

public class UseGetClassMethod {
	public static void main(String[] args) {

		Computer2 com = new Computer2();
		NotePc6 npc = new NotePc6();

		System.out.println("comオブジェクトのクラスは" + com.getClass() + "です。");
		System.out.println("npcオブジェクトのクラスは" + npc.getClass() + "です。");
	}
}

実行結果

解説

 6行目と7行目ではComputer2クラスとNotePc6クラスのオブジェクトを生成しています。
   6:Computer2 com = new Computer2();
   7:NotePc6 npc = new NotePc6();

 9行目、10行目では、各オブジェクトからgetClassメソッドを呼び出して、そのオブジェクトが属しているクラスの情報を画面に出力しています。
   9: System.out.println("comオブジェクトのクラスは" + com.getClass() + "です。");
   10: System.out.println("npcオブジェクトのクラスは" + npc.getClass() + "です。");

 実行結果からも分かるように、そのオブジェクトが属するクラス情報が正しく表示されています。

ポイント
  • ObjectクラスのgetClassメソッドを利用すると、そのオブジェクトが属するクラスの情報が分かる。

 Javaのクラスは必ずObjectクラスのメンバを継承しているので、基本的な機能でも使い方によっては大変便利なものになります。今回紹介したメンバやその他のメンバについても忘れないようにして下さい。


NEXT>> 1.6 本章のまとめ