Pourquoi une variable «Class» ne peut-elle pas être transmise à instanceof?

89

Pourquoi ce code ne se compile-t-il pas?

    public boolean isOf(Class clazz, Object obj){
        if(obj instanceof clazz){
            return true;
        }else{
            return false;
        }
    }

Pourquoi je ne peux pas passer une variable de classe à instanceof?

eric2323223
la source

Réponses:

131

L' instanceofopérateur travaille sur des types de référence, comme Integer, et non sur des objets, comme new Integer(213). Vous voulez probablement quelque chose comme

clazz.isInstance(obj)

Note latérale: votre code sera plus concis si vous écrivez

public boolean isOf(Class clazz, Object obj){
    return clazz.isInstance(obj)
}

Je ne sais pas vraiment si vous avez besoin d'une méthode plus, cependant.

Robert Munteanu
la source
Je sais que le code est totalement inutile, je veux juste démontrer ma confusion :)
eric2323223
6
Integern'est pas un littéral de classe. Integer.classserait un littéral de classe (voir § 15.8.2 du JLS: java.sun.com/docs/books/jls/third_edition/html/… ). L' instanceofopérateur prend un "ReferenceType" (aka un nom de type) comme spécifié au § 15.20.2 du JLS: java.sun.com/docs/books/jls/third_edition/html/…
Joachim Sauer
3
J'utiliserais clazz.isInstance(obj)puisque l'objet est déjà fourni.
Donal Fellows
13

instanceofne peut être utilisé qu'avec des noms de classe explicites (indiqués au moment de la compilation). Afin de faire une vérification d' exécution , vous devez faire:

clazz.isInstance(obj)

Cela présente un petit avantage clazz.isAssignableFrom(..)car il traite obj == nullmieux le cas .

Eyal Schneider
la source
5

Comme d'autres l'ont mentionné, vous ne pouvez pas passer une variable de classe à instanceofcar une variable de classe fait référence à une instance d'un objet , alors que la main droite de instanceofdoit être un type . Autrement dit, instanceofcela ne signifie pas "y est une instance de l'objet x", cela signifie "y est une instance de type X". Si vous ne connaissez pas la différence entre un objet et un type, considérez:

Object o = new Object();

Ici, le type est Objectet oest une référence à l'instance de l'Object avec ce type. Donc:

if(o instanceof Object)

est valide mais

if(o instanceof o)

n'est pas parce que osur le côté droit se trouve un objet, pas un type.

Plus spécifique à votre cas, une instance de classe n'est pas un type, c'est un objet (qui est créé pour vous par la JVM). Dans votre méthode, Classest un type, mais clazzest un objet (enfin, une référence à un objet)

Vous avez besoin d'un moyen de comparer un objet à un objet de classe. Il se trouve que c'est populaire si ce vous est fourni en tant que méthode de la classe Object: isInstance().

Voici le Java Doc pour isInstance, qui explique mieux cela:

public boolean isInstance(Object obj)

Détermine si l'objet spécifié est compatible avec l'affectation avec l'objet représenté par cette classe. Cette méthode est l'équivalent dynamique de l'opérateur instanceof du langage Java. La méthode retourne true si l'argument Object spécifié est non nul et peut être converti en type de référence représenté par cet objet Class sans déclencher d'exception ClassCastException. Sinon, elle renvoie false.

Plus précisément, si cet objet Class représente une classe déclarée, cette méthode retourne true si l'argument Object spécifié est une instance de la classe représentée (ou de l'une de ses sous-classes); il retourne false sinon. Si cet objet Class représente une classe tableau, cette méthode retourne true si l'argument Object spécifié peut être converti en objet de la classe tableau par une conversion d'identité ou par une conversion de référence élargie; il retourne false sinon. Si cet objet Class représente une interface, cette méthode renvoie true si la classe ou toute superclasse de l'argument Object spécifié implémente cette interface; il retourne false sinon. Si cet objet Class représente un type primitif, cette méthode renvoie false.

Paramètres: obj - l'objet à vérifier
Renvoie: true si obj est une instance de cette classe
Depuis: JDK1.1

Rick Hanlon II
la source
3

Tout d'abord, instanceofexige que l'opérande de droite soit une classe réelle (par exemple obj instanceof Objectou obj instanceof Integer) et non une variable de typeClass . Deuxièmement, vous avez fait une erreur de débutant assez courante que vous ne devriez vraiment pas faire ... le modèle suivant:

si (  expression_conditionnelle ) {
    retourne vrai;
} autre{
    retourner faux;
}

Ce qui précède peut être refactorisé en:

return expression_conditionnelle ;

Vous devez toujours effectuer cette refactorisation, car elle élimine une instruction if ... else redondante. De même, l'expression est refactorable au même résultat.return conditional_expression ? true : false;

Michael Aaron Safyan
la source
2
Ce n’est pas une erreur. Peut-être maladroit mais tout à fait correct. Peut-être que vous voulez du code supplémentaire avant de revenir dans un avenir prévisible ...
L'incroyable