instanceof と型パターン
Object のまま受け取ると、何も呼べない
設定ファイルから読んだ値のように、「入っているものが Object としか分からない」変数があります。中身が Boolean でも Double でも、宣言された型が Object である以上、そのままでは Object のメソッドしか呼べません。
いきなりキャストすれば呼べますが、予想が外れたときは ClassCastException で実行時に落ちます。落とさずに済ませるには、キャストの前に型を確かめる必要があります。
確かめて、その場で受け取る
変数 instanceof 型名 新しい変数名 と書くと、型の判定と取り出しが 1 行で終わります。
Java
static String label(Object v) {
if (v instanceof Boolean b) {
return b ? "オン" : "オフ";
}
if (v instanceof Double d) {
return d + " 秒";
}
return "未対応";
}v の中身が Boolean のときだけ if の中に入り、そこでは b が Boolean 型の変数として使えます。キャストはコンパイラが入れてくれるので、型名を書き間違えて別の型でキャストする事故が起きません。
宣言した変数を使えるのは、判定が真だと分かっている範囲だけです。&& の右側なら安全に使えます。
Java
if (v instanceof Double d && d > 0) {
System.out.println("正の値です");
}|| でつないだ場合は、判定が偽でも右側に到達しうるため使えません。そこもコンパイラが見てくれます。
以前は
if (v instanceof Double) { Double d = (Double) v; ... }と、確かめてからもう一度キャストを書いていました。いまは上の形だけ覚えれば足ります。
null は必ず false になる
instanceof は左辺が null のとき、右にどんな型を書いても false を返します。null かどうかを別に確かめる必要はありません。逆に「null のときだけ別扱いしたい」なら、instanceof より前に自分で if (v == null) を書きます。
分岐が増えてきたら switch でも同じ型パターンが使えます。case Boolean b -> のように書けて、case null も枝の 1 本として置けます。
やってみよう
describeObject(Object o) を完成させてください。見分ける型は 2 つです。
oがStringのとき、"String:length="に文字数をつなげて返すoがIntegerのとき、"Integer:"に値をつなげて返す- どちらでもないとき (
Doubleやnullを含む) は"Other"を返す
型パターンで受け取った変数から length() を呼べば、キャストは 1 つも書かずに済みます。空文字は文字数 0 なので "String:length=0"、null は手順 3 に落ちて "Other" になります。
要件
o instanceof Stringで String 判定をして、"String:length=" + 文字数を返すことo instanceof Integerで Integer 判定をして、"Integer:" + 値を返すこと- 上記いずれにも該当しない場合 (Double, null など) は
"Other"を返すこと
入出力例
describeObject("hello") → "String:length=5"
describeObject("") → "String:length=0"
describeObject(42) → "Integer:42"
describeObject(0) → "Integer:0"
describeObject(3.14) → "Other"