Javaでinstanceofの代わりに使えるClassクラスのメソッドはisInstanceとisAssignableFromだというメモ

タイトル通り。

使おうと思うたびに「 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 演算子とは、左辺と右辺が逆になる。

Javadoc

指定された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 を引数にとる。

Javadoc

このClassオブジェクトが表すクラスまたはインタフェースが、指定されたClassパラメータが表すクラスまたはインタフェースと等しいかどうか、あるいはそのスーパー・クラスあるいはスーパー・インタフェースであるかどうかを判定します。

instanceofClass#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 を使うのが好み。

振り返り

レガシーなコードに手を入れている時、 instanceofif else で5個くらいつながっていたので、書き直そうと思ったが、どうしても isAssignableFrom が思い出せなかった。

老化がヤバい。