「サブ」クラスじゃないやん!
質問:「サブクラス」の「サブ」には「予備」といった語感がありますが、サブクラスはスーパークラスのフィールド・メソッドも持っているので、むしろサブクラスの方が「スーパーなクラス」じゃないですか? 語感とイメージが一致しません。
解答:それは勘違いです。サブクラスはスーパークラスのフィールド・メソッドなんて持っていませんよ?
恐らく皆さんは「サブクラスって実はスーパーじゃね?」と疑問に思うことでしょう。
サブクラスはスーパークラスのフィールド・メソッドが使えてさらに自分のフィールド・メソッドまで使えるわけですから、「スーパー」と「サブ」が逆なんじゃ、と思われるかもしれません。
でもよく考えてみましょう。本当にサブクラスはスーパークラスのフィールド・メソッドを持っていますか?
「5.2 継承で機能を加える」で紹介したNormalSuperクラスとAddedSubクラスで考えてみましょう。
/**
* 普通のクラス。
* (SuperClassと全く同じクラスです)
*/
class NormalSuper
{
// int型変数のdataフィールドです。
int data;
/**
* フィールドを出力するメソッドです。
*/
void printData()
{
System.out.println( data );
}
}
/**
* NormalSuperクラスから継承した、サブクラス。
* フィールドとメソッドを追加しています。
*/
class AddedSub extends NormalSuper
{
// int型変数のdataSubフィールドです。
int dataSub;
/**
* フィールドを出力するメソッドです。
*/
void printDataSub()
{
// このクラスで追加したフィールドを出力。
System.out.println( dataSub );
// ついでにスーパークラスのフィールドも出力。
System.out.println( data );
}
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class AddedSubRunner
{
public static void main( String[] args )
{
// インスタンスを1つ作り数値を入れます。
AddedSub ref = new AddedSub();
// スーパークラスのフィールドに値を入れて出力します。
ref.data = 100;
ref.printData();
// 出力結果:
// 100
// サブクラスのフィールドに値を入れて出力します。
ref.dataSub = 200;
ref.printDataSub();
// 出力結果:
// 200
// 100
}
}
// AddedSubRunner.java /** * 普通のクラス。 * (SuperClassと全く同じクラスです) */ class NormalSuper { // int型変数のdataフィールドです。 int data; /** * フィールドを出力するメソッドです。 */ void printData() { System.out.println( data ); } } /** * NormalSuperクラスから継承した、サブクラス。 * フィールドとメソッドを追加しています。 */ class AddedSub extends NormalSuper { // int型変数のdataSubフィールドです。 int dataSub; /** * フィールドを出力するメソッドです。 */ void printDataSub() { // このクラスで追加したフィールドを出力。 System.out.println( dataSub ); // ついでにスーパークラスのフィールドも出力。 System.out.println( data ); } } /** * 実行用クラス。このクラスを実行してください。 */ class AddedSubRunner { public static void main( String[] args ) { // インスタンスを1つ作り数値を入れます。 AddedSub ref = new AddedSub(); // スーパークラスのフィールドに値を入れて出力します。 ref.data = 100; ref.printData(); // 出力結果: // 100 // サブクラスのフィールドに値を入れて出力します。 ref.dataSub = 200; ref.printDataSub(); // 出力結果: // 200 // 100 } }
NormalSuperクラスがスーパークラスです。
* 普通のクラス。
* (SuperClassと全く同じクラスです)
*/
class NormalSuper
{
// int型変数のdataフィールドです。
int data;
/**
* フィールドを出力するメソッドです。
*/
void printData()
{
System.out.println( data );
}
}
/** * 普通のクラス。 * (SuperClassと全く同じクラスです) */ class NormalSuper { // int型変数のdataフィールドです。 int data; /** * フィールドを出力するメソッドです。 */ void printData() { System.out.println( data ); } }
そしてAddedSubクラスがサブクラスです。
* NormalSuperクラスから継承した、サブクラス。
* フィールドとメソッドを追加しています。
*/
class AddedSub extends NormalSuper
{
// int型変数のdataSubフィールドです。
int dataSub;
/**
* フィールドを出力するメソッドです。
*/
void printDataSub()
{
// このクラスで追加したフィールドを出力。
System.out.println( dataSub );
// ついでにスーパークラスのフィールドも出力。
System.out.println( data );
}
}
/** * NormalSuperクラスから継承した、サブクラス。 * フィールドとメソッドを追加しています。 */ class AddedSub extends NormalSuper { // int型変数のdataSubフィールドです。 int dataSub; /** * フィールドを出力するメソッドです。 */ void printDataSub() { // このクラスで追加したフィールドを出力。 System.out.println( dataSub ); // ついでにスーパークラスのフィールドも出力。 System.out.println( data ); } }
よく見てみましょう。AddedSubクラスに、NormalSuperクラスは入っていますか? 入っていません。あくまでNormalSuperクラスとAddedSubクラスは別々です。継承をしても、スーパークラスとサブクラスがくっついちゃってるわけじゃないんです。
「でもサブクラスを通してスーパークラスのフィールド・メソッドが使えるじゃないか」と思うかもしれません。でもそれはちょっと違います。
「サブクラスを通して」じゃないんです。
「サブクラスのインスタンスを通して」なんです。
「サブクラスのインスタンス」は、スーパークラスのインスタンスも持っています。そのため、サブクラスのインスタンスを通して、スーパークラスのインスタンスが持つフィールドやメソッドを使うことができます。
そう。
つまり「すごい」のはサブクラスのインスタンスなのです。サブクラスのインスタンスはスーパークラスのインスタンスも持っているわけですから、スーパークラスのインスタンス単体よりすごいわけです。
でもこれは、あくまで「サブクラスのインスタンス」。「サブクラスそのもの」じゃありません。サブクラスはサブクラスであって、インスタンスとは別物です。
また、「サブクラスのインスタンス」を「サブインスタンス」とは言いません。
「サブクラスのインスタンス」は常に「スーパークラスのインスタンス」を持っています。
「スーパークラスのインスタンス」を持たない「サブクラスのインスタンス」はありません。
なので、「サブクラスのインスタンス」は常に「スーパークラスのインスタンス」より「すごい」わけです。
クラスはインスタンスの設計図です。
スーパークラスとサブクラスに設計図が書かれていて、それらを元にインスタンスを作ります。
できたインスタンスは、各設計図によって作られた「1つの実体」というわけです。