Como determinar a classe de um objeto?

510

Se classe Be classe Cestendem classe Ae eu tenho um objeto do tipo Bou C, como posso determinar de que tipo é uma instância?

transportadora
fonte
14
@ starblue Fundição seria a primeira coisa que vem à mente. Duvido que a instância do operador exista se não houver necessidade.
b1nary.atr0phy
@ b1nary.atr0phy não seria bom usar primeiro a isnancia do operador. Se há um elenco para um tipo incompatível, acredito que irá resultar em uma ClassCastException
committedandroider

Respostas:

801
if (obj instanceof C) {
//your code
}
IAdapter
fonte
31
É útil anotar a verificação inversa ou como verificar se um Objeto NÃO é uma instância de uma classe:if(!(obj instanceof C))
Dzhuneyt
32
Eu acredito que o método getClass () é a resposta para a pergunta original. Nesse caso (a instância obj de A) também forneceria saída "true", mas a intenção é encontrar a classe de tempo de execução do objeto na imagem. Se Parent1 for estendido por Child1 e Child2, tente o seguinte code Child1 child1 = new Child1 (); Parent1 parentChild = new Child2 (); Filho2 filho2 = novo Filho2 (); (instância child1 do Parent1); (instância child1 de Child1); (instância parentChild de Child2); (parentChild instanceof Parent1); (instância parentChild de Child1); code , pode limpar a intenção de instanceof.
Bhavesh Agarwal
Definitivamente uma alternativa para a construção de uma interface
JohnMerlino
3
E se eu tiver duas classes implementando interface única? Como faço para distinguir a classe exata do objeto?
olyv
3
Uma coisa, porém, não funciona se obj for nulo. A solução seria então ParentInterface.class.isAssignableFrom (Child.class)
alexbt
351

Use Object.getClass () . Retorna o tipo de tempo de execução do objeto.

Bill the Lizard
fonte
12
Na verdade, é assim que você determina a classe de um objeto
AA_PV 18/17
resposta impecável @ Bill
gaurav
1
Não sei por que isso não é o mais popular resposta
eicksl
178

Várias respostas corretas foram apresentadas, mas ainda existem mais métodos: Class.isAssignableFrom()e simplesmente tentar lançar o objeto (que pode lançar a ClassCastException).

Formas possíveis resumidas

Vamos resumir as maneiras possíveis de testar se um objeto objé uma instância do tipo C:

// Method #1
if (obj instanceof C)
    ;

// Method #2
if (C.class.isInstance(obj))
    ;

// Method #3
if (C.class.isAssignableFrom(obj.getClass()))
    ;

// Method #4
try {
    C c = (C) obj;
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

// Method #5
try {
    C c = C.class.cast(obj);
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

Diferenças no nullmanuseio

Há uma diferença no nullmanuseio:

  • Nos 2 primeiros métodos, as expressões avaliam falsese objé null( nullnão é instância de nada).
  • O terceiro método jogaria um NullPointerExceptionobviamente.
  • Os métodos 4 e 5, pelo contrário, aceitam nullporque nullpodem ser convertidos para qualquer tipo!

Lembrar: null não é uma instância de nenhum tipo, mas pode ser convertida para qualquer tipo.

Notas

  • Class.getName()não deve ser usado para executar um teste "is-instance-of" porque, se o objeto não for do tipo, Cmas uma subclasse dele, ele pode ter um nome e pacote completamente diferentes (portanto, os nomes das classes obviamente não coincidem), mas é ainda do tipo C.
  • Pela mesma herança, o motivo Class.isAssignableFrom()não é simétrico :
    obj.getClass().isAssignableFrom(C.class)retornaria falsese o tipo de objfosse uma subclasse de C.
icza
fonte
6
Este é realmente um excelente resumo de muitas das armadilhas dos diferentes métodos. Obrigado por uma escrita tão completa!
Kelsin 8/08/2015
32

Você pode usar:

Object instance = new SomeClass();
instance.getClass().getName(); //will return the name (as String) (== "SomeClass")
instance.getClass(); //will return the SomeClass' Class object

HTH. Mas acho que na maioria das vezes não é uma boa prática usar isso para controlar o fluxo ou algo semelhante ...

Johannes Weiss
fonte
Eu o usei para criar um logger genérico; por isso, enviei um objeto para o logger e ele faz logon, dependendo do nome da classe do objeto, em vez de fornecer a tag ou a string de log sempre. obrigado
MBH
24

Qualquer uso de qualquer um dos métodos sugeridos é considerado um cheiro de código, baseado em um projeto de OO ruim.

Se o seu design for bom, você não precisará usar getClass()ou instanceof.

Qualquer um dos métodos sugeridos servirá, mas apenas algo a ter em mente, em termos de design.

Yuval Adam
fonte
3
Sim, provavelmente 99% dos usos de getClass e instanceof podem ser evitados com chamadas de método polimórficas.
Bill o Lagarto
3
Eu concordo. Neste caso, estou trabalhando com objetos gerados a partir de xml, seguindo um esquema mal projetado, do qual não possuo propriedade.
transportador
28
Não necessariamente. Às vezes, a separação de interfaces é boa. Há momentos em que você deseja saber se A é um B, mas não deseja tornar obrigatório que A seja um B, pois somente A é necessário para a maioria das funcionalidades - B possui funcionalidade opcional.
MetroidFan2002 12/02/09
8
Além disso, há momentos em que você precisa garantir que o objeto seja da mesma classe com a qual você está comparando; por exemplo, eu gosto de substituir o método equals do objeto quando crio minha própria classe. Eu sempre verifico que o objeto que entra é da mesma classe.
precisa
58
Além disso, eu diria que dizer às pessoas que algo está ruim sem explicar exatamente o porquê ou fazer uma referência a um artigo, livro ou qualquer outro recurso em que a questão seja explicada é considerada não construtiva. Portanto, e sabendo que estou no StackOverflow, não sei por que as pessoas votaram tanto nessa resposta. Algo está mudando aqui ...
Adrián Pérez
15

Podemos usar a reflexão neste caso

objectName.getClass().getName();

Exemplo:-

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String name = request.getClass().getName();
}

Nesse caso, você obterá o nome da classe que o objeto passa para a HttpServletRequestvariável de referência de interface.

user1884500
fonte
isto está correto. usando apenas obj.getClass()retornará o className, prefixex pela palavraclass
x6iae
request.getClass().getName();imprime todo o pacote! juntamente com o nome da classe
shareef
13

Também existe um .isInstancemétodo na Classclasse " ". se você obtiver a classe de um objeto via, myBanana.getClass()poderá ver se o objeto myAppleé uma instância da mesma classe que myBananavia

myBanana.getClass().isInstance(myApple)
Andreas Petersson
fonte
1

verificar com isinstance()não seria suficiente se você quiser saber em tempo de execução. usar:

if(someObject.getClass().equals(C.class){
    // do something
}
Alon Gouldman
fonte
0

Eu uso a função blow na minha classe GeneralUtils, verifique se pode ser útil

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}
Ahmed Salem
fonte
0

Usei os genéricos do Java 8 para obter qual é a instância do objeto em tempo de execução, em vez de precisar usar o caso do comutador

 public <T> void print(T data) {
    System.out.println(data.getClass().getName()+" => The data is " + data);
}

transmita qualquer tipo de dado e o método imprimirá o tipo de dado que você passou enquanto o chamava. por exemplo

    String str = "Hello World";
    int number = 10;
    double decimal = 10.0;
    float f = 10F;
    long l = 10L;
    List list = new ArrayList();
    print(str);
    print(number);
    print(decimal);
    print(f);
    print(l);
    print(list);

A seguir está a saída

java.lang.String => The data is Hello World
java.lang.Integer => The data is 10
java.lang.Double => The data is 10.0
java.lang.Float => The data is 10.0
java.lang.Long => The data is 10
java.util.ArrayList => The data is []
Saurabh Verma
fonte