Verifique se um Objeto de Classe é uma subclasse de outro Objeto de Classe em Java

196

Estou brincando com a API de reflexão do Java e tentando lidar com alguns campos. Agora, eu estou preso em identificar o tipo dos meus campos. Cordas são fáceis, basta fazer myField.getType().equals(String.class). O mesmo se aplica a outras classes não derivadas. Mas como verifico classes derivadas? Por exemplo, LinkedListcomo subclasse de List. Não consigo encontrar qualquer isSubclassOf(...)ou extends(...)método. Preciso percorrer tudo getSuperClass()e encontrar minha supeclasse sozinha?

craesh
fonte
11
LinkedListnão é uma subclasse de List. É uma implementação de List.
TJ Crowder
2
Sub-tipo pode ser um termo melhor
jpaugh

Respostas:

402

Você deseja este método:

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

em geral, List(acima) deve ser substituído por superclasse myClassdeve ser substituído porsubclass

No JavaDoc :

Determina se a classe ou interface representada por este Classobjeto é igual ou é uma superclasse ou superinterface da classe ou interface representada pelo Classparâmetro especificado . Retorna truese sim; caso contrário, ele retorna false. Se este Classobjeto representar um tipo primitivo, esse método retornará truese o Classparâmetro especificado for exatamente esse Classobjeto; caso contrário, ele retorna false.

Referência:


Palavras-chave:

a) Verifique se um objeto é uma instância de uma classe ou interface (incluindo subclasses) que você conhece em tempo de compilação:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Exemplo:

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

b) Verifique se um Objeto é uma instância de uma Classe ou Interface (incluindo subclasses) que você conhece apenas em tempo de execução:

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

Exemplo:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}
Sean Patrick Floyd
fonte
20
Observe o esquema: SUPERCLASS.isAssignableFrom(SUBCLASS)Isso me confundiu primeiro, embora seja realmente óbvio considerando o nome.
código é o seguinte
7
@TrudleR Concordo. Algo como SUPERCLASS.isExtendedBy(SUBCLASS)seria muito mais fácil de entender
Sean Patrick Floyd
@SeanPatrickFloyd, na verdade, isExtendedByé um nome ruim, como CLASS.isAssignableFrom(CLASS)seria verdadeiro (e, portanto CLASS.isExtendedBy(CLASS), também). Isso não seria o que eu esperava.
Qw3ry
@ Qw3ry sim, eu estou supondo que é também o que os autores Api pensou :-)
Sean Patrick Floyd
24

Outra opção é instanceof:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}
Landei
fonte
Boa chamada (+1). E depois há também a combinação dos dois mecanismos: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/...
Sean Patrick Floyd
5
Isso implicaria que você instancia isso Field. Mas eu só quero "olhar" para a minha classe e seus campos, não quero "experimentá-los".
craesh
Eu vejo esse método muito mais limpo e claro do que o modo "isAssignableFrom", no caso de você precisar verificar a árvore de herança de um objeto.
Cbuchart
Tenha em mente que instanceoftambém trabalha para o pai (neste caso Number) se não só das crianças
lukaszrys
9

instanceof funciona em instâncias, ou seja, em Objetos. Às vezes você deseja trabalhar diretamente com as aulas. Nesse caso, você pode usar o método asSubClass da classe Class. Alguns exemplos:

1)

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

isso ocorrerá sem problemas porque o JFrame é a subclasse de Object. c conterá um objeto Class que representa a classe JFrame.

2)

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

isso iniciará um java.lang.ClassCastException porque JFrame NÃO é uma subclasse de JButton. c não será inicializado.

3)

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

isso ocorrerá sem problemas porque o JFrame implementa a interface java.io.Serializable. c conterá um objeto Class que representa a classe JFrame.

Obviamente, as importações necessárias devem ser incluídas.

Marco
fonte
5

Isso funciona para mim:

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;
}
Para Kra
fonte
1
Funciona bem, mas pode ser necessário adicionar uma verificação nula após clazz = clazz.getSuperclass (), caso você acione java.lang.Object que não possui uma super classe.
Jonas Pedersen
4

Esta é uma versão aprimorada da resposta da @ schuttek. Ele foi aprimorado porque retorna corretamente false para primitivas (por exemplo, isSubclassOf (int.class, Object.class) => false) e também manipula corretamente interfaces (por exemplo, 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
fonte
3

Um método recursivo para verificar se a Class<?>é uma subclasse de outra Class<?>...

Versão melhorada do @Ao Kra 's resposta :

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

//Herança

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

// Teste o 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
fonte