Qual das alternativas a seguir é melhor?
a instanceof B
ou
B.class.isAssignableFrom(a.getClass())
A única diferença que eu sei é que, quando 'a' é nulo, o primeiro retorna falso, enquanto o segundo gera uma exceção. Fora isso, eles sempre dão o mesmo resultado?
java
instanceof
reflection
Megamug
fonte
fonte
Respostas:
Ao usar
instanceof
, você precisa conhecer a classeB
em tempo de compilação. Ao usá-isAssignableFrom()
lo, pode ser dinâmico e mudar durante o tempo de execução.fonte
a instanceof Bref.getClass()
. como essa pode ser a resposta aceita com tão pouca explicação (ou a falta dela)?a instanceof Bref
não éa instanceof Bref.class
. O segundo argumento para o operador instanceof é um nome de classe, não uma expressão resolvida para uma instância de objeto de classe.B.class.isAssignableFrom(a.getClass())
, B é conhecido ea instanceof B
é melhor. Direita?instanceof
só pode ser usado com tipos de referência, não tipos primitivos.isAssignableFrom()
pode ser usado com qualquer objeto de classe:Vejo http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
fonte
Falando em termos de desempenho:
TL; DR
Use Instância ou instância com desempenho semelhante. isAssignableFrom é um pouco mais lento.
Ordenado por desempenho:
Com base em uma referência de 2000 iterações no JAVA 8 Windows x64, com 20 iterações de aquecimento.
Em teoria
Usando um visualizador de código de byte suave , podemos converter cada operador em bytecode.
No contexto de:
JAVA:
Bytecode:
JAVA:
Bytecode:
JAVA:
Bytecode:
Medindo quantas instruções de código de byte são usadas por cada operador, podemos esperar que instanceof e isInstance sejam mais rápidos que isAssignableFrom . No entanto, o desempenho real NÃO é determinado pelo bytecode, mas pelo código da máquina (que depende da plataforma). Vamos fazer um micro benchmark para cada um dos operadores.
A referência
Crédito: Conforme recomendado por @ aleksandr-dubinsky, e obrigado a @yura por fornecer o código base, aqui está uma referência da JMH (consulte este guia de ajuste ):
Forneceu os seguintes resultados (a pontuação é um número de operações em uma unidade de tempo ; portanto, quanto maior a pontuação, melhor):
Atenção
instanceof
no contexto do seu código pode ser otimizado mais facilmente do que umisInstance
por exemplo ...Para dar um exemplo, faça o seguinte loop:
Graças ao JIT, o código é otimizado em algum momento e obtemos:
Nota
Originalmente, este post estava fazendo seu próprio benchmark usando um loop for em JAVA bruto, o que forneceu resultados não confiáveis, pois algumas otimizações como Just In Time podem eliminar o loop. Portanto, ele media principalmente quanto tempo o compilador JIT levou para otimizar o loop: consulte Teste de desempenho independente do número de iterações para obter mais detalhes
Perguntas relacionadas
fonte
instanceof
é um bytecode que usa essencialmente a mesma lógica quecheckcast
(o bytecode por trás da conversão). É inerentemente mais rápido do que as outras opções, independentemente do grau de otimização do JITC.isAssignableFrom()
é dinâmico.Um equivalente mais direto a
a instanceof B
éIsso funciona (retorna falso) quando
a
estánull
também.fonte
Além das diferenças básicas mencionadas acima, há uma diferença sutil principal entre instanceof operator e o métodoAssignableFrom em Class.
Leia
instanceof
como "esta (a parte esquerda) é a instância desta ou de qualquer subclasse desta (a parte direita)" e leiax.getClass().isAssignableFrom(Y.class)
como "Posso escreverX x = new Y()
". Em outras palavras, instanceof operator verifica se o objeto esquerdo é o mesmo ou subclasse da classe direita, enquantoisAssignableFrom
verifica se podemos atribuir objeto da classe de parâmetro (from) à referência da classe na qual o método é chamado.Observe que ambos consideram a instância real e não o tipo de referência.
Considere um exemplo de 3 classes A, B e C em que C estende B e B estende A.
fonte
b instanceof A
é equivalente aA.class.isAssignableFrom(b.getClass())
(como o OP notou). Seu exemplo é correto, mas irrelevante.new Y()
pode não ser legal seY
for abstrato ou sem construtor público padrão, você pode dizer queX x = (Y)null
é legal se e somente sex.getClass().isAssignableFrom(Y.class)
for verdadeiro.Há também outra diferença:
instância nula de X
false
não importa o que seja Xnull.getClass (). isAssignableFrom (X) lançará uma NullPointerException
fonte
null instanceof X
(onde X é alguma classe conhecida em tempo de compilação) sempre retornaráfalse
.X.class.isAssignableFrom(null.getClass())
, não deveria? Mas sim, chamargetClass()
uma referência nula resultará em NPE.getClass()
, não deve ser usadoisAssignableFrom
em primeiro lugar - a operação é destinada à situação de não ter objetos. Se você tem a referência do objetoa
, o usoa instanceof SomeClass
(se fazer conhecer o tipoSomeClass
) ousomeObject.getClass().isInstance(a)
(se você não sabe o tipo desomeObject
).Há ainda outra diferença. Se o tipo (Classe) a ser testado for dinâmico, por exemplo, passado como um parâmetro do método, instanceof não o cortará para você.
mas você pode fazer:
Ops, vejo que esta resposta já está coberta. Talvez este exemplo seja útil para alguém.
fonte
this
),clazz.isInstance(this)
seria melhor no seu exemplo.Esse tópico me deu uma ideia de como era
instanceof
diferenteisAssignableFrom
, então pensei em compartilhar algo de minha autoria.Eu descobri que usando
isAssignableFrom
a única (provavelmente não a única, mas possivelmente a mais fácil) maneira de perguntar a si mesmo se uma referência de uma classe pode ter instâncias de outra, quando alguém tem instâncias de nenhuma das classes para fazer a comparação.Portanto, não achei que usar o
instanceof
operador para comparar atribuibilidade fosse uma boa idéia quando tudo o que eu tinha eram classes, a menos que eu pensasse em criar uma instância a partir de uma das classes; Eu pensei que isso seria desleixado.fonte
instanceof também não pode ser usado com tipos primitivos ou genéricos. Como no código a seguir:
O erro é: Não é possível executar a verificação da instância no parâmetro T. Use o objeto apagado, pois outras informações genéricas do tipo serão apagadas no tempo de execução.
Não é compilado devido ao apagamento do tipo, removendo a referência de tempo de execução. No entanto, o código abaixo será compilado:
fonte
Considere a seguinte situação. Suponha que você queira verificar se o tipo A é uma superclasse do tipo de obj, você pode ir
... A.class.isAssignableFrom (obj.getClass ()) ...
OU
... obj instance de A ...
Mas a solução isAssignableFrom exige que o tipo de obj seja visível aqui. Se esse não for o caso (por exemplo, o tipo de obj pode ser de uma classe interna privada), essa opção está desativada. No entanto, a instância da solução sempre funcionaria.
fonte
obj
neste exemplo) de qualquer tipo , poderá chamar ogetClass()
método público para obter os metadados de reflexão para a classe de implementação. Isso é verdade mesmo se esse tipo de classe de implementação não estivesse legalmente visível nesse local no momento da compilação. Está tudo bem no tempo de execução porque, para você manter aobj
referência, algum caminho de código que finalmente teve acesso legal à classe criou um e deu (vazou?) Para você.O pseudo-código acima é uma definição de, se referências do tipo / classe A são atribuíveis a partir de referências do tipo / classe B. É uma definição recursiva. Para alguns, pode ser útil, para outros, pode ser confuso. Eu o adiciono no caso de alguém achar útil. Esta é apenas uma tentativa de capturar meu entendimento, não é a definição oficial. Ele é usado em uma certa implementação de Java VM e funciona para muitos programas de exemplo, portanto, embora eu não possa garantir que ele capture todos os aspectos de isAssignableFrom, não está completamente desativado.
fonte
Falando em termos de desempenho "2" (com JMH):
Dá:
Para que possamos concluir: instanceof tão rápido quanto isInstance () e isAssignableFrom () não muito longe (+ 0,9% do tempo de execução). Portanto, não há diferença real, o que você escolher
fonte
Que tal alguns exemplos para mostrá-lo em ação ...
fonte
alguns testes que fizemos em nossa equipe mostram que
A.class.isAssignableFrom(B.getClass())
funciona mais rápido queB instanceof A
. isso pode ser muito útil se você precisar verificar isso em um grande número de elementos.fonte
instanceof
, eu acredito que você tem problemas de design graves ...