実は、全てクラスが Objectクラスを継承する関係になっています。
(java.langパッケージにあります。このパッケージは特別なパッケージで、
このjava.langパッケージに含まれるクラスはimportしなくても使えるようになっています。)
いくつかのクラス図で例を以下に示します
|
全てのクラスの継承元がObjectクラスです。
よって、Objectクラスの変数 o があるとすると、
次のように何でも参照させる代入ができます。
(あるクラスの変数があるとすると、
それでそのクラスのサブクラスオブジェクトも管理(参照)できる規則がありました。
これは、『あるオブジェクトがある時、そのスーパークラスの変数で管理(参照)できる』
ということです。よって、全てのクラスのスーパークラスになっているObject型変数で
何でも管理できることになります。)
Object o;
o = new Scanner(System.in);
o = new Record2();
o = new Record3();
しかし、oが、Record3を参照しているからといって、
そのRecord3が持つdisplayメソッドが直接使えるわけではありません。
Objectクラスに存在しないメソッドを使えば、
コンパイルエラーとなります。
o.display(1);
は、
シンボルを見つけられません。
のエラーです。
Objectクラスの変数は、次のようにキャストを使うことで
指定のクラスのメソッドを使う表現が可能となります。
import rec.Record2; public class Test extends Object{ public static void main(String[] arg){ Object o; o = new Record2(); ((Record2)o).init("A01", 10); ((Record2)o).display(1); } } |
D:\java>java Test 1番目レコード 商品コード:A01 数量:10 D:\\java> |
ですが、実際に参照しているオブジェクトが持っていないメソッドを 実行させることはできません。以下に、実行エラーの例を示します。
import rec.Record2;
import rec.Record3;
public class Test extends Object{
public static void main(String[] arg){
Object o;
o = new Record2();
((Record3)o).init("B02", 20, 200);
((Record2)o).display(1);
}
} |
D:\java>java Test Exception in thread "main" java.lang.ClassCastException: rec.Record2 cannot be cast to rec.Record3 at Test.main(Test.java:9)
これは、 |
o = new Record3();に変更し、((Record2)o).display(1)
の実行でもRecord3のdisplayが呼び出されるのは、ポリモーフィズムの特性です。
オブジェクト指向プログラミングでは、この特性をよく利用するのですが、
理解して使えるようになる上で、最大の難所になっています。
変数oに、その型のサブクラスのオブジェクトを参照できるということは、
実行の場合によって、参照するオブジェクトが異なるクラスになる場合もあるということです。
オーバーロードされているメソッドを使うのであれば問題ありません。
しかしオーバーロードされていないメソッドを使う場合は、
希望のメソッドが使えるクラスかどうかをチェックして使わなければなりません。
その調べる方法の一つで、instanceof演算子を使う方法があります。
これは、変数 instanceof クラス名 と判定式を書き、
変数が参照しているオブジェクトが、クラス名か、
またはそのクラス名の継承クラスであるかを調べて、
そうであれば結果をtrueにします。以下に例を示します。
import rec.Record2; import rec.Record3; public class Test { public static void main(String[] arg){ Object o = new Record2(); if(arg.length>=1 && arg[0].equals("Record3")){ o = new Record3(); } if(o instanceof Record3){ ((Record3)o).init("B02", 20, 200); } else { ((Record2)o).init("A01", 10); } ((Record2)o).display(1); } }
上記では、oがRecord3のオブジェクトか、またはRecord3継承クラスのオブジェクトの場合だけ、
3つの引数を指定するinitメソッドを使っています。
このプログラムは、コマンドラインパラメタで"Record3"を指定した時に、Record3を生成し、
そうでなければRecord2を使うプログラムです。以下に2つの実行例を示します。
D:\java>java Test Record3 1番目レコード 商品コード:B02 数量:20 単価:200 D:\java> |
D:\java>java Test 1番目レコード 商品コード:A01 数量:10 D:\java> |