instanceof Vs getClass ()

114

Vejo ganho no desempenho ao usar operador getClass()e operador.==instanceOf

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

Existe alguma diretriz, qual usar getClass()ou instanceOf?

Dado um cenário: eu conheço as classes exatas a serem correspondidas, ou seja String, Integer(essas são as classes finais), etc.

Está usando uma instanceOfmá prática do operador?

bolha
fonte
3
Isso é explicado em: stackoverflow.com/questions/596462/… .
Clement P
2
Seu método de tempo está causando atrasos artificiais e produzindo resultados de tempo incorretos. Troque a ordem em que você faz as verificações e verá que a primeira verificação que você faz (== ou instanceof) sempre será mais longa. Eu acho que é o println () s. Você nunca deve incluir essas coisas em seu bloco de tempo.
kurtzmarc
Apenas um comentário à parte, para comparar o desempenho, use várias iterações de ciclo (por exemplo, 10.000) para melhorar a precisão. Uma única invocação não é uma boa medida.
martins.tuga

Respostas:

140

A razão pela qual o desempenho de instanceofe getClass() == ...é diferente é que eles estão fazendo coisas diferentes.

  • instanceoftesta se a referência do objeto no lado esquerdo (LHS) é uma instância do tipo no lado direito (RHS) ou algum subtipo .

  • getClass() == ... testa se os tipos são idênticos.

Portanto, a recomendação é ignorar o problema de desempenho e usar a alternativa que fornece a resposta de que você precisa.

Usar o instanceOfoperador é uma prática ruim?

Não necessariamente. O uso excessivo de um instanceOfou outro getClass() pode ser "cheiro de design". Se você não for cuidadoso, acabará com um design em que a adição de novas subclasses resulta em uma quantidade significativa de retrabalho de código. Na maioria das situações, a abordagem preferida é usar polimorfismo.

No entanto, há casos em que NÃO são "cheiro de design". Por exemplo, equals(Object)você precisa testar o tipo real do argumento e retornar falsese ele não corresponder. É melhor fazer isso usando getClass().


Termos como "melhor prática", "má prática", "cheiro de design", "antipadrão" e assim por diante devem ser usados ​​com moderação e tratados com suspeita. Eles encorajam o pensamento preto-ou-branco. É melhor fazer seus julgamentos no contexto, em vez de baseados puramente em dogmas; por exemplo, algo que alguém disse é "melhor prática".

Stephen C
fonte
@StephenC Como você disse, é code smellpara usar qualquer um. Isso significa que é uma consequência de um código de design ruim (não polimórfico) que leva você a usar qualquer um deles. posso inferir o uso de qualquer um deles desta forma?
overexchange
@overexchange - 1) Eu disse "overuse" e não "use". 2) Tirando isso, não entendo o que você está perguntando. O que você quer dizer com "inferir o uso ..." ??? O código usa essas coisas ou não usa.
Stephen C
Eu inferi que o uso de instanceof& getClass()entra em cena devido ao mau design existente (não polimórfico) do código. estou correcto?
overexchange
5
@overexchange - Você não pode inferir validamente que todo uso de instanceof(por exemplo) é um design ruim. Existem situações em que pode ser a melhor solução. O mesmo para getClass(). Vou repetir que disse "overuse" e não "use" . Cada caso precisa ser julgado por seus méritos ... não pela aplicação cega de alguma regra dogmática infundada.
Stephen C
44

Você deseja corresponder exatamente a uma classe , por exemplo, apenas correspondendo em FileInputStreamvez de qualquer subclasse de FileInputStream? Se sim, use getClass()e ==. Eu normalmente faria isso em um equals, de forma que uma instância de X não fosse considerada igual a uma instância de uma subclasse de X - caso contrário, você pode ter problemas de simetria complicados. Por outro lado, isso geralmente é mais útil para comparar que dois objetos são da mesma classe do que de uma classe específica.

Caso contrário, use instanceof. Observe que com getClass()você precisará garantir que tem uma referência não nula para começar, ou você obterá um NullPointerException, enquanto instanceofapenas retornará falsese o primeiro operando for nulo.

Pessoalmente, eu diria que instanceofé mais idiomático - mas usar qualquer um deles extensivamente é um cheiro de design na maioria dos casos.

Jon Skeet
fonte
18

Eu sei que já faz um tempo desde que isso foi perguntado, mas eu aprendi uma alternativa ontem

Todos nós sabemos que você pode fazer:

if(o instanceof String) {   // etc

mas e se você não souber exatamente que tipo de aula precisa ser? você não pode fazer genericamente:

if(o instanceof <Class variable>.getClass()) {   

pois dá um erro de compilação.
Em vez disso, aqui está uma alternativa - isAssignableFrom ()

Por exemplo:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
Andy Dingfelder
fonte
8
Não use isAssignableFrom. A maneira correta de escrever o instanceof Stringusando reflexão é String.getClass().isInstance(o). O javadoc até diz isso: este método é o equivalente dinâmico do instanceofoperador da linguagem Java .
Andreas
3

getClass () tem a restrição de que os objetos são iguais apenas a outros objetos da mesma classe, o mesmo tipo de tempo de execução, conforme ilustrado na saída do código abaixo:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

Saídas:

SubClass estende ParentClass. subClassInstance é instanceof ParentClass.

GetClass () diferente retorna resultados com subClassInstance e parentClassInstance.

Saurav Sahu
fonte