タイトル通り。
使おうと思うたびに「 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 が思い出せなかった。
老化がヤバい。