Sprawdź, czy obiekt klasy jest podklasą innego obiektu klasy w Javie

196

Bawię się z interfejsem API odbicie Java i próbuję obsłużyć niektóre pola. Teraz utknąłem w identyfikacji typu moich pól. Ciągi są łatwe, po prostu zrób myField.getType().equals(String.class). To samo dotyczy innych klas niepochodzących. Ale jak mogę sprawdzić klasy pochodne? Np. LinkedListJako podklasa List. Nie mogę znaleźć żadnej metody isSubclassOf(...)ani extends(...)metody. Czy muszę przejść wszystko getSuperClass()i znaleźć własną klasę własną?

craesh
źródło
11
LinkedListnie jest podklasą List. Jest to realizacja od List.
TJ Crowder
2
Podtyp może być lepszym terminem
jpaugh

Odpowiedzi:

402

Chcesz tę metodę:

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

gdzie ogólnie List(powyżej) należy zastąpić superclassi myClassnależy je zastąpićsubclass

Z JavaDoc :

Określa, czy klasa lub interfejs reprezentowany przez ten Classobiekt jest taki sam, jak też nadklasa lub superinterface klasy lub interfejsu reprezentowanego przez określony Classparametr. Zwraca, truejeśli tak; w przeciwnym razie powróci false. Jeśli ten Classobiekt reprezentuje typ pierwotny, ta metoda zwraca, truejeśli podanym Classparametrem jest właśnie ten Classobiekt; w przeciwnym razie powróci false.

Odniesienie:


Związane z:

a) Sprawdź, czy obiekt jest instancją klasy lub interfejsu (w tym podklas), które znasz w czasie kompilacji:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Przykład:

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

b) Sprawdź, czy obiekt jest instancją klasy lub interfejsu (w tym podklas), które znasz tylko w czasie wykonywania:

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

Przykład:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}
Sean Patrick Floyd
źródło
20
Zwróć uwagę na schemat: SUPERCLASS.isAssignableFrom(SUBCLASS)Najpierw mnie to pomyliło, chociaż w rzeczywistości jest to oczywiste, biorąc pod uwagę nazewnictwo.
codepleb
7
@TrudleR Zgadzam się. Coś takiego SUPERCLASS.isExtendedBy(SUBCLASS)byłoby znacznie łatwiejsze do zrozumienia
Sean Patrick Floyd
@SeanPatrickFloyd faktycznie isExtendedByjest złym imieniem, co CLASS.isAssignableFrom(CLASS)byłoby prawdą (i dlatego CLASS.isExtendedBy(CLASS)też). Nie tego się spodziewałem.
Qw3ry,
@ Qw3ry tak, zakładam, że tak też myśleli autorzy Api :-)
Sean Patrick Floyd
24

Inną opcją jest instanceof:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}
Landei
źródło
Dobra rozmowa (+1). I jest też kombinacja dwóch mechanizmów: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
Sean Patrick Floyd
5
Oznaczałoby to, że to robisz Field. Ale chcę tylko „spojrzeć” na moją klasę i jej pola, nie chcę „wypróbowywać”.
craesh
Widzę tę metodę o wiele czystszą i jaśniejszą niż metoda „isAssignableFrom”, w przypadku, gdy trzeba sprawdzić drzewo dziedziczenia obiektu.
cbuchart
Należy pamiętać, że instanceofdziała również dla Numbersamego rodzica (w tym przypadku ) nie tylko dla dzieci
lukaszrys
9

instanceof działa na instancjach, tj. na Obiektach. Czasami chcesz pracować bezpośrednio z klasami. W takim przypadku możesz użyć metody asSubClass klasy Class. Kilka przykładów:

1)

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

przejdzie to płynnie, ponieważ JFrame jest podklasą Object. c będzie zawierać obiekt klasy reprezentujący klasę JFrame.

2)

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

spowoduje to uruchomienie java.lang.ClassCastException ponieważ JFrame NIE jest podklasą JButton. c nie zostanie zainicjowane.

3)

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

przejdzie to płynnie, ponieważ JFrame implementuje interfejs java.io.Serializable. c będzie zawierać obiekt klasy reprezentujący klasę JFrame.

Oczywiście należy uwzględnić potrzebny import.

Marco
źródło
5

To działa dla mnie:

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;
}
Do Kra
źródło
1
Działa ładnie, ale może być konieczne dodanie kontroli zerowej po clazz = clazz.getSuperclass () w przypadku trafienia w java.lang.Object, który nie ma superklasy.
Jonas Pedersen
4

To jest ulepszona wersja odpowiedzi @ schuttek. Jest poprawiony, ponieważ poprawnie zwraca false dla prymitywów (np. IsSubclassOf (int.class, Object.class) => false), a także poprawnie obsługuje interfejsy (np. 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;
    }
}
użytkownik2415587
źródło
3

Metoda rekurencyjna sprawdzająca, czy a Class<?>jest podklasą innej Class<?>...

Ulepszona wersja @To kra „s odpowiedź :

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);
    }
}
schuttek
źródło
3

//Dziedzictwo

    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'";
        }
    }

// Metody

    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;
        }
      }
    }

// Przetestuj kod

    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));

//Wynik

    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
joseluisbz
źródło