タイトル通り。
使おうと思うたびに「 instanceof
演算子の代わりに使えるメソッドなんだっけ?」となるのでメモ。
環境
OpenJDK 8 8.262.10。
それぞれの使い方
instanceof 演算子
instanceOf
ではない。
インスタンス(参照型) instanceof クラス/インターフェース名
と記述。
以下の条件に該当すれば true
、該当しなければ false
を返す。
- 右辺がクラス名の場合、左辺が右辺で指定したクラス、またはサブクラスのインスタンス
- 右辺がインターフェース名の場合、左辺が右辺で指定したインターフェース、またはそのサブインターフェースを実装している
後述のClassクラスのメソッドの説明を借りると、「左辺が右辺と代入互換の関係にあるか」を判定する。
地味に便利なのは、左辺のインスタンスが null
でも例外は発生せず、 false
を返してくれる。
Object str = "str"; assert str instanceof String; assert str instanceof CharSequence; assert str instanceof Object; Object sb = new StringBuilder("sb"); assert !(sb instanceof String); assert sb instanceof CharSequence; assert sb instanceof Object; Object nil = null; assert !(nil instanceof String); assert !(nil instanceof CharSequence); assert !(nil instanceof Object);
Class#isInstance(Object)
Class<?>.isInstance(インスタンス)
のように記述。
instanceof
演算子とは、左辺と右辺が逆になる。
指定されたObjectが、このClassが表すオブジェクトと代入互換の関係にあるかどうかを判定します。このメソッドは、Java言語のinstanceof演算子と動的に等価です。
こちらも、引数として渡すインスタンスが null
でも、例外は発生しない。
Object str = "str"; assert String.class.isInstance(str); assert CharSequence.class.isInstance(str); assert Object.class.isInstance(str); Object sb = new StringBuilder("sb"); assert !String.class.isInstance(sb); assert CharSequence.class.isInstance(sb); assert Object.class.isInstance(sb); Object nil = null; assert !String.class.isInstance(nil); assert !CharSequence.class.isInstance(nil); assert !Object.class.isInstance(nil);
Class#isAssignableFrom(Class<?>)
Class<?>.isAssignableFrom(Class<?>)
のように記述。こちらはインスタンスではなく、 Class
を引数にとる。
このClassオブジェクトが表すクラスまたはインタフェースが、指定されたClassパラメータが表すクラスまたはインタフェースと等しいかどうか、あるいはそのスーパー・クラスあるいはスーパー・インタフェースであるかどうかを判定します。
instanceof
や Class#isInstance(Object)
との違いとして、 null
を渡すと NullPointerException
が発生する。
Class<?> strClass = String.class; assert String.class.isAssignableFrom(strClass); assert CharSequence.class.isAssignableFrom(strClass); assert Object.class.isAssignableFrom(strClass); Class<?> sbClass = StringBuilder.class; assert !String.class.isAssignableFrom(sbClass); assert CharSequence.class.isAssignableFrom(sbClass); assert Object.class.isAssignableFrom(sbClass); Class<?> objClass = Object.class; assert !String.class.isAssignableFrom(objClass); assert !CharSequence.class.isAssignableFrom(objClass); assert Object.class.isAssignableFrom(objClass); try { Object.class.isAssignableFrom(null); assert false; } catch (NullPointerException e) { assert true; } catch (Exception e) { assert false; }
引数として渡すインスタンスが null
でなければ、 Class.isInstance(obj) == Class.isAssignableFrom(obj.getClass())
となる。
注意点
Class#isInstance(Object)
に、 Class
を渡してもコンパイルエラーにならない。
昔、それが原因のバグを修正する羽目になったので、それからは null
チェックしてから getClass()
して Class#isAssignableFrom
を使うのが好み。
振り返り
レガシーなコードに手を入れている時、 instanceof
が if else
で5個くらいつながっていたので、書き直そうと思ったが、どうしても isAssignableFrom
が思い出せなかった。
老化がヤバい。