Vérifier si un objet de classe est une sous-classe d'un autre objet de classe en Java


198

Je joue avec l'API de réflexion de Java et j'essaie de gérer certains champs. Maintenant, je suis obligé d'identifier le type de mes champs. Les cordes sont faciles, faites-le myField.getType().equals(String.class). Il en va de même pour les autres classes non dérivées. Mais comment vérifier les classes dérivées? Par exemple, en LinkedListtant que sous-classe de List. Je ne trouve aucune méthode isSubclassOf(...)ni aucune extends(...)méthode. Dois-je parcourir tout getSuperClass()et trouver ma superclass par moi-même?


11
LinkedListn'est pas une sous-classe de List. C'est une implémentation de List.
TJ Crowder

2
Le sous-type pourrait être un meilleur terme
jpaugh

Réponses:


404

Vous voulez cette méthode:

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

où en général, List(ci-dessus) doit être remplacé par superclasset myClassdoit être remplacé parsubclass

À partir du JavaDoc :

Détermine si la classe ou l'interface représentée par cet Classobjet est la même que, ou est une superclasse ou une super-interface de, la classe ou l'interface représentée par le Classparamètre spécifié . Il retourne truesi c'est le cas; sinon, il revient false. Si cet Classobjet représente un type primitif, cette méthode renvoie truesi le Classparamètre spécifié est exactement cet Classobjet; sinon, il revient false.

Référence:


En relation:

a) Vérifiez si un objet est une instance d'une classe ou d'une interface (y compris les sous-classes) que vous connaissez au moment de la compilation:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Exemple:

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

b) Vérifiez si un objet est une instance d'une classe ou d'une interface (y compris les sous-classes) que vous ne connaissez qu'au moment de l'exécution:

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

Exemple:

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

21
Notez le schéma: SUPERCLASS.isAssignableFrom(SUBCLASS)Cela m'a d'abord confondu, bien que cela soit en fait évident compte tenu de la dénomination.
codepleb

7
@TrudleR Je suis d'accord. Quelque chose comme SUPERCLASS.isExtendedBy(SUBCLASS)serait beaucoup plus facile à comprendre
Sean Patrick Floyd

@SeanPatrickFloyd isExtendedByest en fait un mauvais nom comme ce CLASS.isAssignableFrom(CLASS)serait vrai (et donc CLASS.isExtendedBy(CLASS)aussi). Ce ne serait pas ce à quoi je m'attendais.
Qw3ry

@ Qw3ry oui, je suppose que c'est aussi ce que les auteurs d'API pensaient :-)
Sean Patrick Floyd

25

Une autre option est instanceof:

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

Bon appel (+1). Et puis il y a aussi la combinaison des deux mécanismes: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/...
Sean Patrick Floyd

5
Cela impliquerait que vous instanciez cela Field. Mais je veux juste "regarder" ma classe et ses champs, je ne veux pas "les essayer".
craesh

Je vois cette méthode beaucoup plus propre et plus claire que la méthode "isAssignableFrom", dans le cas où vous devez vérifier l'arbre d'héritage d'un objet.
cbuchart le

Gardez à l'esprit que cela instanceoffonctionne également pour le parent (dans ce cas Number) lui-même non seulement pour les enfants
lukaszrys

9

instanceof fonctionne sur des instances, c'est-à-dire sur des objets. Parfois, vous souhaitez travailler directement avec les classes. Dans ce cas, vous pouvez utiliser asSubClass méthode de la classe Class. Quelques exemples:

1)

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

cela se déroulera sans problème car JFrame est une sous-classe d'Object. c contiendra un objet Class représentant la classe JFrame.

2)

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

cela lancera une exception java.lang.ClassCastException exception car JFrame n'est PAS une sous-classe de JButton. c ne sera pas initialisé.

3)

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

cela se passera sans problème car JFrame implémente l'interface java.io.Serializable. c contiendra un objet Class représentant la classe JFrame.

Bien entendu, les importations nécessaires doivent être incluses.


5

Cela fonctionne pour moi:

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
Fonctionne bien, mais vous devrez peut-être ajouter une vérification nulle après clazz = clazz.getSuperclass () au cas où vous frapperiez java.lang.Object qui n'a pas de super classe.
Jonas Pedersen

4

Ceci est une version améliorée de la réponse de @ schuttek. Il est amélioré car il renvoie correctement false pour les primitives (par exemple isSubclassOf (int.class, Object.class) => false) et gère également correctement les interfaces (par exemple 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

Une méthode récursive pour vérifier si a Class<?>est une sous-classe d'une autreClass<?> ...

Version améliorée de la réponse de @To Kra :

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

//Héritage

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

// Méthodes

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

// Tester le 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));

//Résultat

    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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.