instanceof 演算子Revised: Mar./9th/2002
前節までで見てきた通り、オブジェクト型変数同士の代入が許されるのは、参照するオブジェクトが、そのクラス型に対応するインスタンスを持っているかどうかです。サブクラスをインスタンス化したオブジェクトは、明らかにスーパークラスのインスタンスを含んでいるので、サブクラス型オブジェクトはスーパークラス型変数に代入できます。その逆は、必ずしも可能ではなく、可能であっても明示的にキャストが必要でした。
オブジェクトが、特定のクラスのインスタンスを含んでいるのか評価するのが intstanceof 演算子です。演算子の左辺に任意の参照、右辺にはクラス/配列/インタフェースを記述します。
InstanceTest.java:
//Date クラスのインポート
import java.util.Date;
class InstanceTest {
public static void main(String[] args) {
Date obj = new Date();
boolean bln = (obj instanceof Date);
System.out.println(bln);
System.out.println(obj);
}
}
ここでは標準クラスライブラリの Date クラスをインスタンス化しています。このクラスを利用するためには、2行目のように、このクラスが含まれているパッケージも明示した完全限定名をインポートするのが普通です。
このようにして作ったオブジェクトを参照する変数 obj が、本当に Date クラスのインスタンスを参照しているのかチェックしています。
C:\Java>javac InstanceTest.java C:\Java>java InstanceTest true Sat Mar 09 22:34:54 JST 2002
java.lang.Object クラスは全てのクラス継承階層のトップですから、この型の変数には任意のクラス型の値を代入できます。次のサンプルは、引数に受け取ったオブジェクトの型によって動作を変えるメソッドのサンプルです。
InstanceChk.java:
class Sml1 {
void whois() {
System.out.println("Sml1です。");
}
}
class Sml2 {
void whois() {
System.out.println("Sml2です。");
}
}
class InstanceChk {
public static void main(String[] args) {
//インスタンス化
Sml1 obj1 = new Sml1();
Sml2 obj2 = new Sml2();
//メソッド呼び出し
obj1.whois();
objChk(obj1);
obj2.whois();
objChk(obj2);
}
static void objChk(Object obj) {
if (obj instanceof Sml1) {
System.out.println("このクラスは知っています。");
} else {
System.out.println("そんなクラスは知りません。");
}
}
}
二つのクラスを作成し、それを別々にインスタンス化しています。それぞれのオブジェクトを参照する変数を、 java.lang.Object 型としてメソッド引数に渡して、そのインスタンスをチェックしています。
C:\Java>javac InstanceChk.java C:\Java>java InstanceChk Sml1です。 このクラスは知っています。 Sml2です。 そんなクラスは知りません。
サブクラス型オブジェクトへの参照は、スーパークラス型変数に代入できます。この場合は明示的な型変換は必要なく、代入先のスーパークラス型に自動型変換されます。この変数はスーパークラス型ですが、参照している実体はサブクラスのインスタンスも含んでいるはずです。従って、元のサブクラス型に型変換することが可能なのですが、この場合は明示的にキャストする必要があります。
「サブクラス型 --> スーパークラス型 --> サブクラス型」と型変換/代入を繰り返していき、その都度参照先の実体が持つインスタンスを調べてみましょう。
CastChk.java:
class Parent {
void whois() {
System.out.println("私は親。");
}
}
class Child extends Parent {
void whois() {
System.out.println("私は子供。");
}
}
class CastChk {
public static void main(String[] args) {
//インスタンス化
Child obj1 = new Child();
obj1.whois();
System.out.print(" Child: " + (obj1 instanceof Child));
System.out.println(" Parent: " + (obj1 instanceof Parent));
//型変換
Parent obj2 = obj1;
obj2.whois();
System.out.print(" Child: " + (obj2 instanceof Child));
System.out.println(" Parent: " + (obj2 instanceof Parent));
//キャスト
Child obj3 = (Child)obj2;
obj3.whois();
System.out.print(" Child: " + (obj3 instanceof Child));
System.out.println(" Parent: " + (obj3 instanceof Parent));
}
}
ここには、スーパークラス Parent とそのサブクラス Child が存在します。サブクラスのオブジェクトを作成し、その参照を Child 型、 Parent 型、 Child 型に型変換しています。
また、メソッド whois() がオーバーライドされていることにも注目してください。
C:\Java>javac CastChk.java
C:\Java>java CastChk
私は子供。
Child: true Parent: true
私は子供。
Child: true Parent: true
私は子供。
Child: true Parent: true
型変換によって、参照している実体が持つインスタンスに変化が無いことに注目してください。そのために、スーパークラス型であっても、サブクラスでオーバーライドされたメソッドが使われているのです。