Überprüfen Sie, ob ein Klassenobjekt eine Unterklasse eines anderen Klassenobjekts in Java ist

196

Ich spiele mit Javas Reflection API herum und versuche, mit einigen Feldern umzugehen. Jetzt bin ich nicht mehr in der Lage, den Typ meiner Felder zu identifizieren. Saiten sind einfach, machen Sie es einfach myField.getType().equals(String.class). Gleiches gilt für andere nicht abgeleitete Klassen. Aber wie überprüfe ich abgeleitete Klassen? ZB LinkedListals Unterklasse von List. Ich kann keine isSubclassOf(...)oder extends(...)Methode finden. Muss ich durch alles gehen getSuperClass()und meine Oberklasse selbst finden?

Craesh
quelle
11
LinkedListist keine Unterklasse von List. Es ist eine Implementierung von List.
TJ Crowder
2
Subtyp könnte ein besserer Begriff sein
jpaugh

Antworten:

402

Sie möchten diese Methode:

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

wo in der Regel List( siehe oben) sollte ersetzt werden superclassund myClasssollte ersetzt werden durchsubclass

Aus dem JavaDoc :

Legt fest, ob die von diesem ClassObjekt dargestellte Klasse oder Schnittstelle mit der durch den angegebenen ClassParameter dargestellten Klasse oder Schnittstelle identisch oder eine Oberklasse oder Superschnittstelle ist. Es kehrt zurück, truewenn ja; Andernfalls wird es zurückgegeben false. Wenn dieses ClassObjekt einen primitiven Typ darstellt, gibt diese Methode zurück, truewenn der angegebene ClassParameter genau dieses ClassObjekt ist. Andernfalls wird es zurückgegeben false.

Referenz:


Verbunden:

a) Überprüfen Sie, ob ein Objekt eine Instanz einer Klasse oder Schnittstelle (einschließlich Unterklassen) ist, die Sie zur Kompilierungszeit kennen:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Beispiel:

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

b) Überprüfen Sie, ob ein Objekt eine Instanz einer Klasse oder Schnittstelle (einschließlich Unterklassen) ist, die Sie nur zur Laufzeit kennen:

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

Beispiel:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}
Sean Patrick Floyd
quelle
20
Beachten Sie das Schema: SUPERCLASS.isAssignableFrom(SUBCLASS)Dies verwirrte mich zuerst, obwohl es angesichts der Benennung tatsächlich offensichtlich ist.
Codepleb
7
@TrudleR Ich stimme zu. So etwas SUPERCLASS.isExtendedBy(SUBCLASS)wäre viel einfacher zu verstehen
Sean Patrick Floyd
@ SeanPatrickFloyd ist eigentlich isExtendedByein schlechter Name, wie CLASS.isAssignableFrom(CLASS)es wahr wäre (und daher CLASS.isExtendedBy(CLASS)auch). Das würde ich nicht erwarten.
Qw3ry
@ Qw3ry ja, ich nehme an, das haben auch die Api-Autoren gedacht :-)
Sean Patrick Floyd
24

Eine andere Option ist Instanz von:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}
Landei
quelle
Guter Anruf (+1). Und dann gibt es noch die Kombination der beiden Mechanismen: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
Sean Patrick Floyd
5
Dies würde bedeuten, dass Sie das instanziieren Field. Aber ich möchte nur meine Klasse und ihre Felder "anschauen", nicht "ausprobieren".
Craesh
Ich sehe diese Methode viel sauberer und klarer als die "isAssignableFrom" -Methode, falls Sie den Vererbungsbaum eines Objekts überprüfen müssen.
Cbuchart
Denken Sie daran, dass instanceofauch für Eltern (in diesem Fall Number) selbst nicht nur Kinder
funktioniert
9

instanceof arbeitet mit Instanzen, dh mit Objekten. Manchmal möchten Sie direkt mit Klassen arbeiten. In diesem Fall können Sie die asSubClass verwenden Methode der Class-Klasse verwenden. Einige Beispiele:

1)

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

Dies läuft reibungslos ab, da JFrame eine Unterklasse von Object ist. c enthält ein Class-Objekt, das die JFrame-Klasse darstellt.

2)

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

Dadurch wird eine java.lang.ClassCastException gestartetDadurch wird gestartet, da JFrame NICHT die Unterklasse von JButton ist. c wird nicht initialisiert.

3)

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

Dies wird reibungslos ablaufen, da JFrame die Schnittstelle java.io.Serializable implementiert. c enthält ein Class-Objekt, das die JFrame-Klasse darstellt.

Natürlich müssen die benötigten Importe einbezogen werden.

Marco
quelle
5

Das funktioniert bei mir:

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;
}
Zu Kra
quelle
1
Funktioniert gut, aber Sie müssen möglicherweise nach clazz = clazz.getSuperclass () eine Nullprüfung hinzufügen, falls Sie auf java.lang.Object klicken, das keine Superklasse hat.
Jonas Pedersen
4

Dies ist eine verbesserte Version der Antwort von @ schuttek. Es wurde verbessert, weil es für Grundelemente korrekt false zurückgibt (z. B. isSubclassOf (int.class, Object.class) => false) und auch Schnittstellen korrekt verarbeitet (z. B. 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;
    }
}
user2415587
quelle
3

Eine rekursive Methode, um zu überprüfen, ob a Class<?>eine Unterklasse einer anderen Class<?>...

Verbesserte Version des @An Kra ‚s Antwort :

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
quelle
3

//Erbe

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

// Methoden

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

// Teste den Code

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

//Ergebnis

    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
quelle