Lequel des énoncés suivants est le meilleur?
a instanceof B
ou
B.class.isAssignableFrom(a.getClass())
La seule différence que je sache, c'est que lorsque «a» est nul, le premier renvoie faux, tandis que le second lève une exception. A part ça, donnent-ils toujours le même résultat?
java
instanceof
reflection
Megamug
la source
la source
Réponses:
Lors de l'utilisation
instanceof
, vous devez connaître la classe deB
au moment de la compilation. Lors de son utilisation,isAssignableFrom()
il peut être dynamique et changer pendant l'exécution.la source
a instanceof Bref.getClass()
. comment cela peut-il être la réponse acceptée avec si peu d'explications (ou son absence)?a instanceof Bref
ne l' est pasa instanceof Bref.class
. Le deuxième argument de l'opérateur instanceof est un nom de classe, pas une expression se résolvant en une instance d'objet de classe.B.class.isAssignableFrom(a.getClass())
, B est connu eta instanceof B
est meilleur. Droite?instanceof
ne peut être utilisé qu'avec des types de référence, pas des types primitifs.isAssignableFrom()
peut être utilisé avec n'importe quel objet de classe:Voir http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
la source
Parler en termes de performances:
TL; DR
Utilisez isInstance ou instanceof qui ont des performances similaires. isAssignableFrom est légèrement plus lent.
Trié par performance:
Basé sur un benchmark de 2000 itérations sur JAVA 8 Windows x64, avec 20 itérations de préchauffage.
En théorie
En utilisant une visionneuse de bytecode douce, nous pouvons traduire chaque opérateur en bytecode.
Dans le contexte de:
JAVA:
Bytecode:
JAVA:
Bytecode:
JAVA:
Bytecode:
En mesurant le nombre d'instructions de bytecode utilisées par chaque opérateur, nous pouvons nous attendre à ce que instanceof et isInstance soient plus rapides que isAssignableFrom . Cependant, les performances réelles ne sont PAS déterminées par le bytecode mais par le code machine (qui dépend de la plateforme). Faisons un micro benchmark pour chacun des opérateurs.
La référence
Crédit: Comme conseillé par @ aleksandr-dubinsky, et merci à @yura d'avoir fourni le code de base, voici un benchmark JMH (voir ce guide de réglage ):
A donné les résultats suivants (le score est un nombre d'opérations dans une unité de temps , donc plus le score est élevé, mieux c'est):
Attention
instanceof
dans le contexte de votre code pourrait être optimisé plus facilement qu'unisInstance
par exemple ...Pour vous donner un exemple, prenez la boucle suivante:
Grâce au JIT, le code est optimisé à un moment donné et nous obtenons:
Remarque
À l'origine, ce post faisait son propre benchmark en utilisant une boucle for dans JAVA brut, ce qui a donné des résultats peu fiables car une optimisation comme Just In Time peut éliminer la boucle. Il s'agissait donc principalement de mesurer le temps nécessaire au compilateur JIT pour optimiser la boucle: voir Test de performances indépendant du nombre d'itérations pour plus de détails
Questions connexes
la source
instanceof
est un bytecode qui utilise essentiellement la même logique quecheckcast
(le bytecode derrière le casting). Il sera intrinsèquement plus rapide que les autres options, quel que soit le degré d'optimisation JITC.isAssignableFrom()
dynamique.Un équivalent plus direct
a instanceof B
estCela fonctionne (retourne faux) quand l'
a
estnull
aussi.la source
Outre les différences de base mentionnées ci-dessus, il existe une différence subtile fondamentale entre l'opérateur instanceof et la méthode isAssignableFrom dans Class.
Lire
instanceof
comme «est-ce (la partie gauche) l'instance de ceci ou n'importe quelle sous-classe de ceci (la partie droite)» et lirex.getClass().isAssignableFrom(Y.class)
comme «Puis-je écrireX x = new Y()
». En d'autres termes, l'opérateur instanceof vérifie si l'objet gauche est le même ou la sous-classe de la classe droite, tandis qu'ilisAssignableFrom
vérifie si nous pouvons affecter l'objet de la classe de paramètres (from) à la référence de la classe sur laquelle la méthode est appelée.Notez que les deux considèrent l'instance réelle et non le type de référence.
Prenons un exemple de 3 classes A, B et C où C s'étend B et B s'étend A.
la source
b instanceof A
est équivalent àA.class.isAssignableFrom(b.getClass())
(comme l'OP l'a remarqué). Votre exemple est correct mais non pertinent.new Y()
peut ne pas être légal siY
est abstrait ou sans constructeur par défaut public, vous pouvez direX x = (Y)null
est légal si et seulement six.getClass().isAssignableFrom(Y.class)
est vrai.Il y a aussi une autre différence:
null instanceof X est
false
quel que soit X estnull.getClass (). isAssignableFrom (X) lèvera une NullPointerException
la source
null instanceof X
(où X est une classe connue au moment de la compilation) retournera toujoursfalse
.X.class.isAssignableFrom(null.getClass())
non? Mais oui, l'appelgetClass()
à une référence nulle se traduira par NPE.getClass()
, ne doit pas être utilisé avecisAssignableFrom
en premier lieu - l'opération est destinée à la situation sans objets. Si vous avez la référence de l' objeta
, l' utilisationa instanceof SomeClass
(si vous faites connaître le typeSomeClass
) ousomeObject.getClass().isInstance(a)
(si vous ne connaissez le type desomeObject
).Il y a encore une autre différence. Si le type (classe) à tester est dynamique, par exemple passé en tant que paramètre de méthode, alors instanceof ne le coupera pas pour vous.
mais vous pouvez faire:
Oups, je vois que cette réponse est déjà couverte. Peut-être que cet exemple est utile à quelqu'un.
la source
this
), ceclazz.isInstance(this)
serait mieux dans votre exemple.Ce fil m'a donné un aperçu de la
instanceof
différenceisAssignableFrom
, j'ai donc pensé partager quelque chose de moi.J'ai trouvé que le fait
isAssignableFrom
d'être le seul (probablement pas le seul, mais peut-être le plus simple) à se demander si une référence d'une classe peut prendre des instances d'une autre, quand on a des instances d'aucune classe pour faire la comparaison.Par conséquent, je n'ai pas trouvé
instanceof
opérateur pour comparer l'assignation était une bonne idée quand tout ce que j'avais était des classes, à moins que j'envisage de créer une instance à partir d'une des classes; Je pensais que ce serait bâclé.la source
instanceof ne peut pas non plus être utilisé avec des types primitifs ou génériques. Comme dans le code suivant:
L'erreur est: Impossible d'effectuer une vérification instanceof par rapport au paramètre de type T. Utilisez plutôt son objet d'effacement car d'autres informations de type génériques seront effacées lors de l'exécution.
Ne compile pas en raison de l'effacement de type supprimant la référence d'exécution. Cependant, le code ci-dessous compilera:
la source
Considérez la situation suivante. Supposons que vous vouliez vérifier si le type A est une super classe du type d'obj, vous pouvez aller soit
... A.class.isAssignableFrom (obj.getClass ()) ...
OU
... obj instanceof A ...
Mais la solution isAssignableFrom nécessite que le type d'obj soit visible ici. Si ce n'est pas le cas (par exemple, le type d'obj peut être d'une classe interne privée), cette option est désactivée. Cependant, la solution instanceof fonctionnerait toujours.
la source
obj
dans cet exemple) de n'importe quel type, vous pouvez appeler lagetClass()
méthode publique dessus pour obtenir les métadonnées de réflexion de la classe d'implémentation. Cela est vrai même si ce type de classe d'implémentation n'est pas légalement visible à cet emplacement au moment de la compilation. Il est OK lors de l' exécution parce que, pour vous de tenir laobj
référence, un certain chemin de code qui a finalement fait avoir un accès légal à la classe créée et a donné une (fuite?) Pour vous.Le pseudo-code ci-dessus est une définition de, si les références de type / classe A sont attribuables à partir de références de type / classe B. Il s'agit d'une définition récursive. Pour certains, cela peut être utile, pour d'autres, cela peut être déroutant. Je l'ajoute au cas où quelqu'un le trouverait utile. Ce n'est qu'une tentative pour saisir ma compréhension, ce n'est pas la définition officielle. Il est utilisé dans une certaine implémentation de machine virtuelle Java et fonctionne pour de nombreux exemples de programmes, donc même si je ne peux pas garantir qu'il capture tous les aspects de isAssignableFrom, il n'est pas complètement désactivé.
la source
Parler en termes de performances "2" (avec JMH):
Il donne:
Pour que nous puissions conclure: instanceof aussi vite que isInstance () et isAssignableFrom () pas loin (+ 0.9% de temps d'exécution). Donc pas de vraie différence quoi que vous choisissiez
la source
Que diriez-vous de quelques exemples pour le montrer en action ...
la source
certains tests que nous avons faits dans notre équipe montrent que cela
A.class.isAssignableFrom(B.getClass())
fonctionne plus vite queB instanceof A
. cela peut être très utile si vous devez vérifier cela sur un grand nombre d'éléments.la source
instanceof
, je crois que vous avez de sérieux problèmes de conception ...