Перевірте, чи об’єкт класу є підкласом іншого об’єкта класу на Java


197

Я граю з API відбиття Java і намагаюся обробити деякі поля. Тепер я застряг у визначенні типу моїх полів. Струни легкі, просто робіть myField.getType().equals(String.class). Те саме стосується інших не похідних класів. Але як перевірити похідні класи? Наприклад, LinkedListяк підклас List. Я не можу знайти жодного способу isSubclassOf(...)чи extends(...)методу. Чи потрібно мені пройти все getSuperClass()і знайти власний суперкласс?


11
LinkedListне є підкласом List. Це впровадження в List.
TJ Crowder

2
Підтип може бути кращим терміном
jpaugh

Відповіді:


403

Ви хочете цей метод:

boolean isList = List.class.isAssignableFrom(myClass);

де загалом List(вище) слід замінити superclassі myClassзамінити йогоsubclass

З JavaDoc :

Визначає, чи клас або інтерфейс, представлений цим Classоб'єктом, або такий самий, або є надкласом або надінтерфейсом класу або інтерфейсу, представленого вказаним Classпараметром. Він повертається, trueякщо так; інакше повертається false. Якщо цей Classоб'єкт являє собою примітивний тип, цей метод повертається, trueякщо вказаний Classпараметр є саме цим Classоб'єктом; інакше повертається false.

Довідка:


Пов'язані:

a) Перевірте, чи об’єкт є екземпляром класу чи інтерфейсу (включаючи підкласи), який ви знаєте під час компіляції:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Приклад:

assertTrue(Arrays.asList("a", "b", "c") instanceof List<?>);

b) Перевірте, чи об'єкт є екземпляром класу чи інтерфейсу (включаючи підкласи), про який ви знаєте лише під час виконання:

Class<?> typeOrInterface = // acquire class somehow
boolean isInstance = typeOrInterface.isInstance(someObject);

Приклад:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}

21
Зверніть увагу на схему: SUPERCLASS.isAssignableFrom(SUBCLASS)Це спочатку мене збентежило, хоча це насправді очевидно з урахуванням іменування.
codepleb

7
@TrudleR Я згоден. Щось подібне SUPERCLASS.isExtendedBy(SUBCLASS)було б набагато простіше зрозуміти
Шон Патрік Флойд

@SeanPatrickFloyd насправді isExtendedByє поганим ім'ям, як це CLASS.isAssignableFrom(CLASS)було б правдою (і, отже, CLASS.isExtendedBy(CLASS)також). Це було б не те, чого я очікував.
Qw3ry

@ Qw3ry так, я припускаю, що це теж думали автори Api :-)
Шон Патрік Флойд

25

Інший варіант - instanceof:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}

Хороший дзвінок (+1). І тоді ще є поєднання двох механізмів: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
Шон Патрік Флойд

5
Це означає, що ви це зробите Field. Але я просто хочу "подивитися" на свій клас та його поля, не хочу "випробувати їх".
craesh

Я вважаю цей метод набагато чистішим і зрозумілішим, ніж спосіб "isAssignableFrom", якщо вам потрібно перевірити дерево спадкування об'єкта.
cbuchart

Майте на увазі, що instanceofтакож працює для батьків (в даному випадку Number) не тільки дитячих
lukaszrys

9

instanceof працює над екземплярами, тобто над об'єктами. Іноді хочеться працювати безпосередньо з класами. У цьому випадку ви можете використовувати метод asSubClass класу Class. Деякі приклади:

1)

    Class o=Object.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

це пройде гладко, оскільки JFrame є підкласом Object. c буде містити об'єкт Class, що представляє клас JFrame.

2)

    Class o=JButton.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

це запустить java.lang.ClassCastException, оскільки JFrame НЕ є підкласом JButton. c не буде ініціалізовано.

3)

    Class o=Serializable.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

це пройде гладко, оскільки JFrame реалізує інтерфейс java.io.Serializable. c буде містити об'єкт Class, що представляє клас JFrame.

Звичайно, необхідно включити необхідний імпорт.


5

Це працює для мене:

protected boolean isTypeOf(String myClass, Class<?> superClass) {
    boolean isSubclassOf = false;
    try {
        Class<?> clazz = Class.forName(myClass);
        if (!clazz.equals(superClass)) {
            clazz = clazz.getSuperclass();
            isSubclassOf = isTypeOf(clazz.getName(), superClass);
        } else {
            isSubclassOf = true;
        }

    } catch(ClassNotFoundException e) {
        /* Ignore */
    }
    return isSubclassOf;
}

1
Добре працює, але вам доведеться додати нульову перевірку після clazz = clazz.getSuperclass (), якщо ви потрапили на java.lang.Object, у якого немає суперкласу.
Йонас Педерсен

4

Це вдосконалена версія відповіді @ schuttek. Він вдосконалюється, оскільки він правильно повертає false для примітивів (наприклад, isSubclassOf (int.class, Object.class) => false), а також правильно обробляє інтерфейси (наприклад, isSubclassOf (HashMap.class, Map.class) => true).

static public boolean isSubclassOf(final Class<?> clazz, final Class<?> possibleSuperClass)
{
    if (clazz == null || possibleSuperClass == null)
    {
        return false;
    }
    else if (clazz.equals(possibleSuperClass))
    {
        return true;
    }
    else
    {
        final boolean isSubclass = isSubclassOf(clazz.getSuperclass(), possibleSuperClass);

        if (!isSubclass && clazz.getInterfaces() != null)
        {
            for (final Class<?> inter : clazz.getInterfaces())
            {
                if (isSubclassOf(inter, possibleSuperClass))
                {
                    return true;
                }
            }
        }

        return isSubclass;
    }
}

3

Рекурсивний метод перевірити, чи Class<?>є підкласом іншого Class<?>...

Покращена версія @To Кра «S відповідь :

protected boolean isSubclassOf(Class<?> clazz, Class<?> superClass) {
    if (superClass.equals(Object.class)) {
        // Every class is an Object.
        return true;
    }
    if (clazz.equals(superClass)) {
        return true;
    } else {
        clazz = clazz.getSuperclass();
        // every class is Object, but superClass is below Object
        if (clazz.equals(Object.class)) {
            // we've reached the top of the hierarchy, but superClass couldn't be found.
            return false;
        }
        // try the next level up the hierarchy.
        return isSubclassOf(clazz, superClass);
    }
}

3

// Спадкування

    class A {
      int i = 10;
      public String getVal() {
        return "I'm 'A'";
      }
    }

    class B extends A {
      int j = 20;
      public String getVal() {
        return "I'm 'B'";
      }
    }

    class C extends B {
        int k = 30;
        public String getVal() {
          return "I'm 'C'";
        }
    }

// Методи

    public static boolean isInheritedClass(Object parent, Object child) {
      if (parent == null || child == null) {
        return false;
      } else {
        return isInheritedClass(parent.getClass(), child.getClass());
      }
    }

    public static boolean isInheritedClass(Class<?> parent, Class<?> child) {
      if (parent == null || child == null) {
        return false;
      } else {
        if (parent.isAssignableFrom(child)) {
          // is child or same class
          return parent.isAssignableFrom(child.getSuperclass());
        } else {
          return false;
        }
      }
    }

// Тестування коду

    System.out.println("isInheritedClass(new A(), new B()):" + isInheritedClass(new A(), new B()));
    System.out.println("isInheritedClass(new A(), new C()):" + isInheritedClass(new A(), new C()));
    System.out.println("isInheritedClass(new A(), new A()):" + isInheritedClass(new A(), new A()));
    System.out.println("isInheritedClass(new B(), new A()):" + isInheritedClass(new B(), new A()));


    System.out.println("isInheritedClass(A.class, B.class):" + isInheritedClass(A.class, B.class));
    System.out.println("isInheritedClass(A.class, C.class):" + isInheritedClass(A.class, C.class));
    System.out.println("isInheritedClass(A.class, A.class):" + isInheritedClass(A.class, A.class));
    System.out.println("isInheritedClass(B.class, A.class):" + isInheritedClass(B.class, A.class));

// Результат

    isInheritedClass(new A(), new B()):true
    isInheritedClass(new A(), new C()):true
    isInheritedClass(new A(), new A()):false
    isInheritedClass(new B(), new A()):false
    isInheritedClass(A.class, B.class):true
    isInheritedClass(A.class, C.class):true
    isInheritedClass(A.class, A.class):false
    isInheritedClass(B.class, A.class):false
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.