Java Language Utilisation de instanceof avec Generics


Exemple

Utiliser des génériques pour définir le type dans instanceof

Considérons la classe générique suivante Example déclaré avec le paramètre formel <T> :

class Example<T> {
    public boolean isTypeAString(String s) {
        return s instanceof T; // Compilation error, cannot use T as class type here
    }
}

Cela provoquera toujours une erreur de compilation car dès que le compilateur compile le source Java en bytecode Java, il applique un processus appelé effacement de type , qui convertit tout le code générique en code non générique, rendant impossible la distinction entre les types T au moment de l'exécution. Le type utilisé avec instanceof doit être reifiable , ce qui signifie que toutes les informations sur le type doivent être disponibles au moment de l'exécution, ce qui n'est généralement pas le cas pour les types génériques.

La classe suivante représente à quoi ressemblent deux classes différentes d' Example , Example<String> et Example<Number> après que les génériques ont été supprimés par type d'effacement :

class Example { // formal parameter is gone
    public boolean isTypeAString(String s) {
        return s instanceof Object; // Both <String> and <Number> are now Object
    }
}

Comme les types ont disparu, la JVM ne peut pas savoir quel type est T


Exception à la règle précédente

Vous pouvez toujours utiliser des caractères génériques sans limite (?) Pour spécifier un type dans l' instanceof comme suit:

    public boolean isAList(Object obj) {
        return obj instanceof List<?>;
    }

Cela peut être utile pour évaluer si une instance obj est une List ou non:

System.out.println(isAList("foo")); // prints false
System.out.println(isAList(new ArrayList<String>()); // prints true
System.out.println(isAList(new ArrayList<Float>()); // prints true

En fait, les caractères génériques non liés sont considérés comme un type reifiable.


Utiliser une instance générique avec instanceof

Le revers de la médaille est que l'utilisation d'une instance t de T avec instanceof est légale, comme le montre l'exemple suivant:

class Example<T> {
    public boolean isTypeAString(T t) {
        return t instanceof String; // No compilation error this time
    }
}

car après le type d'effacement, la classe ressemblera à ceci:

class Example { // formal parameter is gone
    public boolean isTypeAString(Object t) {
        return t instanceof String; // No compilation error this time
    }
}

Étant donné que, même si l'effacement de type se produit de toute façon, la machine virtuelle Java peut maintenant distinguer différents types de mémoire, même s'ils utilisent le même type de référence ( Object ), comme le montre l'extrait suivant:

Object obj1 = new String("foo"); // reference type Object, object type String
Object obj2 = new Integer(11); // reference type Object, object type Integer
System.out.println(obj1 instanceof String); // true
System.out.println(obj2 instanceof String); // false, it's an Integer, not a String