Compruebe si un objeto de clase es una subclase de otro objeto de clase en Java

196

Estoy jugando con la API de reflexión de Java e intentando manejar algunos campos. Ahora estoy atascado con la identificación del tipo de mis campos. Las cuerdas son fáciles, solo hazlo myField.getType().equals(String.class). Lo mismo se aplica para otras clases no derivadas. Pero, ¿cómo verifico las clases derivadas? Por ejemplo, LinkedListcomo subclase de List. No puedo encontrar ninguno isSubclassOf(...)o extends(...)método. ¿Necesito caminar por todogetSuperClass() y encontrar mi supeclase por mi cuenta?

craesh
fuente
11
LinkedListNo es una subclase de List. Es una implementación de List.
TJ Crowder
2
Subtipo podría ser un término mejor
jpaugh

Respuestas:

402

Quieres este método:

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

donde en general, List(arriba) se debe reemplazar con superclassy se myClassdebe reemplazar consubclass

Desde el JavaDoc :

Determina si la clase o interfaz representada por este Classobjeto es la misma o es una superclase o superinterfaz de la clase o interfaz representada por el Classparámetro especificado . Regresa truesi es así; de lo contrario vuelve false. Si este Classobjeto representa un tipo primitivo, este método devuelve truesi el Classparámetro especificado es exactamente este Classobjeto; de lo contrario vuelve false.

Referencia:


Relacionado:

a) Compruebe si un objeto es una instancia de una clase o interfaz (incluidas las subclases) que conoce en tiempo de compilación:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Ejemplo:

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

b) Verifique si un Objeto es una instancia de una Clase o Interfaz (incluidas las subclases) que solo conoce en tiempo de ejecución:

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

Ejemplo:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}
Sean Patrick Floyd
fuente
20
Tenga en cuenta el esquema: SUPERCLASS.isAssignableFrom(SUBCLASS)esto me confundió primero, aunque en realidad es obvio teniendo en cuenta el nombre.
codepleb
77
@TrudleR Estoy de acuerdo. Algo así SUPERCLASS.isExtendedBy(SUBCLASS)sería mucho más fácil de entender
Sean Patrick Floyd
@SeanPatrickFloyd en realidad isExtendedByes un mal nombre como CLASS.isAssignableFrom(CLASS)sería cierto (y, por CLASS.isExtendedBy(CLASS)lo tanto , también). Esto no sería lo que esperaba.
Qw3ry
@ Qw3ry sí, supongo que eso es también lo que pensaron los autores de Api :-)
Sean Patrick Floyd
24

Otra opción es la instancia de:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}
Landei
fuente
Buena llamada (+1). Y luego también está la combinación de los dos mecanismos: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
Sean Patrick Floyd
55
Esto implicaría que instancias eso Field. Pero solo quiero "mirar" a mi clase y sus campos, no quiero "probarlos".
craesh
Veo este método mucho más limpio y claro que la forma "isAssignableFrom", en el caso de que necesite verificar el árbol de herencia de un objeto.
cbuchart
Tenga en cuenta que instanceoftambién funciona para los padres (en este caso Number) en sí no solo para niños
lukaszrys
9

instanceof funciona en instancias, es decir, en objetos. A veces quieres trabajar directamente con las clases. En este caso, puede usar asSubClass método de la clase Class. Algunos ejemplos:

1)

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

esto pasará sin problemas porque JFrame es una subclase de Object. c contendrá un objeto de clase que representa la clase JFrame.

2)

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

esto lanzará una java.lang.ClassCastException porque JFrame NO es una subclase de JButton. c no se inicializará.

3)

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

esto pasará sin problemas porque JFrame implementa la interfaz java.io.Serializable. c contendrá un objeto de clase que representa la clase JFrame.

Por supuesto, deben incluirse las importaciones necesarias.

Marco
fuente
5

Esto funciona para mi:

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;
}
A Kra
fuente
1
Funciona bien, pero es posible que deba agregar una comprobación nula después de clazz = clazz.getSuperclass () en caso de que golpee java.lang.Object que no tiene una superclase.
Jonas Pedersen
4

Esta es una versión mejorada de la respuesta de @ schuttek. Se mejora porque devuelve correctamente falso para primitivas (por ejemplo, isSubclassOf (int.class, Object.class) => false) y también maneja correctamente las interfaces (por ejemplo, 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;
    }
}
usuario2415587
fuente
3

Un método recursivo para verificar si a Class<?>es una subclase de otra Class<?>...

Versión mejorada del @Al Kra 's respuesta :

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

//Herencia

    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étodos

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

// Prueba el código

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

//Resultado

    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
fuente