#注意書き
####使用されるクラスの詳細について
この記事は「ダウンキャストについてわかりやすく書いたった」の続きで書いている。なので、一部のソースコード(Catクラス、Dogクラス、Life_formクラス)などは一番下の「説明に使用したクラスなどの詳細」項目に掲載しておく。
本文は「instanceof演算子とは」からスタートしている。
####アップキャストとダウンキャストについて
本記事ではアップキャストとダウンキャストについて軽くおさらいしているが、もっと
詳しく知りたい人は以下の記事へどうぞ。
#開発環境
####使用テキストエディタ Atom(以下atom -vertion実行結果)
Atom : 1.28.0
Electron: 2.0.3
Chrome : 61.0.3163.100
Node : 8.9.3
####~以下、コマンド「java -version」実行結果~
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
#アップキャストとダウンキャスト
####instanceofの説明に入る前に軽いおさらい
instanceof演算子も、アップキャスト、ダウンキャストと密接に関係している。
そのため、少しおさらいしよう。
アップキャストとは、親クラスインスタンスを子クラスインスタンスで初期化することだ。
これは、設計の段階で子クラスがどれだけ作られるか決まりきっていないような場合でも、引数を親クラスインスタンスにしておくことで、どんな子クラスインスタンスの受け渡しも可能になる点が便利である。
しかし、これには問題もある。先日投稿した「Javaのダウンキャストについてわかりやすく書いたった」で説明した通り、アップキャストを使用した状態では子クラス独自の関数を呼び出せなくなる。
そこでダウンキャストを行うのだが……。
ここからが本題だ。
####中身、なんですか?
以下のプログラムを見て、何が起きるかを予想してみてほしい。
なお、クラスの詳細については「説明に使用したクラスなどの詳細」に載せている。
public class Main{
public static void main(String[] args){
Life_form life_form = new Life_form();
java.util.Random r = new java.util.Random();
if( r.nextInt(2) == 0 ){
life_form = new Cat();
}else{
life_form = new Dog();
}
//ダウンキャストからの独自関数呼び出し。
Cat lifo = (Cat)life_form;
lifo.catPunch();
}
}
プログラムの説明をしよう。
ランダムな数字を生成し、0だったならばCatインスタンスを、1だったならばDogインスタンスをアップキャストしている。
そして、Catクラスにダウンキャストして、Catクラス独自の関数catPunch()を呼び出そうとしている。
実行して見ると、catPunch()がうまく呼ばれている場合と、ClassCastExceptionエラーになっている場合と二つある。
生成されたインスタンスがCatのものだった場合のみ、正常に動作しているというのが見て取れるだろう。
つまり、逆に言えば、Dogインスタンスが生成されたらエラーになってしまうということだ。
当然だろう。if文のブロックを見ればわかるように、Life_formインスタンスの実体はDogインスタンスの可能性もあるのだ。
無理やりCatインスタンスにダウンキャストしようとしても、実体がDogインスタンスなのにCatインスタンスになれるわけがない。
子クラス独自の関数を呼びたいなら、親クラスインスタンスの実体が何かわかっていなければならないのだ。
#instanceof演算子
このように、せっかくアップキャストで子クラスインスタンスを網羅的に保持できても、中身が分からなければ適切なキャストができず、結果的に子クラス独自の関数も呼ぶことができない。
これは不便だ。
インスタンスの実体が調べたい。
それを実現するためにinstanceof演算子があるのである。
インスタンス instanceof 型名
この構文でインスタンスの実体がなんなのかを調べることができる。
インスタンスの実体と型名が一致しているならtrueとなる。一致していなければもちろんfalseが戻り値として返ってくる。
これを踏まえて先ほどのプログラムの手直ししたものを下記に示す。
####成功例
public class Main{
public static void main(String[] args){
Life_form life_form = new Life_form();
java.util.Random r = new java.util.Random();
if( r.nextInt(2) == 0 ){
life_form = new Cat();
}else{
life_form = new Dog();
}
//インスタンス instanceof 型名
if( life_form instanceof Cat ){
Cat cat = (Cat)life_form;
cat.catPunch();
}else{
Dog dog = (Dog)life_form;
dog.dogAttack();
}
}
}
きちんと、実体別の振る舞いが出力されている。
if文条件式のinstanceof演算子によって適切なダウンキャストが実現できている点に注目だ。
また、生成されたインスタンス独自の関数がきちんと呼べている点も確認してほしい。
このように、instanceof演算子を使うことで安全なダウンキャストを実現することができるのだ。
#まとめ
- instanceof演算子は、```
インスタンス instanceof 型名
- instanceof演算子を使えば、インスタンスの実体別に振る舞いを変えることが可能になる。
- instanceof演算子を使うことで、アップキャストされた子クラスインスタンス独自の関数を使いたい時に、安全なダウンキャストを実現できる。
#説明に使用したクラスなどの詳細
```Life_form.java
//親クラス
public class Life_form{
public void makeSound(){
System.out.println("???");
}
}
public class Cat extends Life_form{
@Override
public void makeSound(){
System.out.println("にゃあ");
}
public void catPunch(){
System.out.println("ネコパン");
}
}
public class Dog extends Life_form {
@Override
public void makeSound(){
System.out.println("クゥーン!");
}
public void dogAttack(){
System.out.println("かみつく");
}
}