На первый взгляд instanceof и Class.isAssignableFrom в Java делают одно и то же. Я уже описывал действие instanceof в своём учебнике, здесь мы заострим внимание на его отличии от Class.isAssignableFrom, который я ещё не рассматривал и не описывал. Оба метода позволяют проверить, является ли переменная экземпляром объекта указанного типа или экземпляром дочернего типа к указанному. Но на самом деле есть три существенные разницы.
Пусть у нас есть следующая структура классов:
1 2 3 4 5 6 7 |
static class A{} static class B extends A {} static class C extends B {} static class D extends C {} |
Объявим две переменные:
1 2 3 |
B b = new C(); Object obj = new C(); B mynull = null; |
С помощью instanceof мы можем проверить, является ли переменная b экземпляром нужного нам типа или дочерним типом к нужному нам:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if (b instanceof A) { // true System.out.println("b instanceof A"); } if (b instanceof B) { // true System.out.println("b instanceof B"); } if (b instanceof C) { // true System.out.println("b instanceof C"); } if (b instanceof D) { // false System.out.println("b instanceof D"); } |
То же самое мы можем сделать и с помощью метода Class.isAssignableFrom, но нам нужно будет поменять местами правую и левую части:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
if (A.class.isAssignableFrom(b.getClass())) { // true System.out.println("A.class isAssignableFrom b.getClass()"); } if (B.class.isAssignableFrom(b.getClass())) { // true System.out.println("B.class isAssignableFrom b.getClass()"); } if (C.class.isAssignableFrom(b.getClass())) { // true System.out.println("C.class isAssignableFrom b.getClass()"); } if (D.class.isAssignableFrom(b.getClass())) { // false System.out.println("D.class isAssignableFrom b.getClass()"); } |
Так вот. Первое отличие instanceof и Class.isAssignableFrom в Java заключается в том, что у них меняются местами левые и правые части.
Есть ещё одно важное отличие. Посмотрите на этот код, он не компилируется:
1 2 3 4 |
// Doesn't compile. Cannot class at runtime with instanceof if (b instanceof obj.getClass()) { } |
Для instanceof тип класса, на принадлежность которому мы проверяем, должен быть известен на этапе компиляции.
Но мы можем сделать это с помощью Class.isAssignableFrom:
1 2 3 4 |
if (obj.getClass().isAssignableFrom(b.getClass())) { System.out.println("obj.getClass() isAssignableFrom b.getClass()"); } |
С помощью Class.isAssignableFrom мы можем проверить принадлежность типу или его потомку даже в том случае, когда тип, на принадлежность которому мы проверяем, на этапе компиляции неизвестен.
Если в левой части instanceof стоит null, то результат будет false:
1 2 3 4 |
if (mynull instanceof B) { // false System.out.println("mynull instanceof B"); } |
Однако мы не можем осуществить подобную проверку с помощью Class.isAssignableFrom:
1 2 3 4 5 6 7 |
if (B.class.isAssignableFrom(mynull.getClass())) { // NullPointerException System.out.println("B.class isAssignableFrom mynull.getClass()"); } if (B.class.isAssignableFrom(null)) { // NullPointerException System.out.println("B.class isAssignableFrom mynull"); } |
Запомните! Для null-значений в левой части instanceof возвращает false, но Class.isAssignableFrom для null-значений в правой части вернёт NullPointerException.