2010-10-09 4 views
6

Dans le code suivant, le type de x est I (bien que x implémente aussi J mais n'est pas connu à la compilation), alors pourquoi le code (1) n'entraîne pas une erreur de compilation. Parce qu'au moment de la compilation, seul le type de la référence est pris en compte.Pourquoi ce code instanceof fonctionne-t-il et ne provoque pas une erreur de compilation?

public class MyClass { 
    public static void main(String[] args) { 
     I x = new D(); 
     if (x instanceof J) //(1) 
      System.out.println("J"); 
    } 
} 

interface I {} 

interface J {} 

class C implements I {} 

class D extends C implements J {} 
+1

Note latérale - s'il vous plaît ne pas oublier d'ajouter un tag pour la langue. J'ai ajouté "java" pour vous. – EboMike

+0

désolé je devrais avoir – user439526

Répondre

12

instanceof est utilisé pour déterminer le type d'un objet à l'exécution. Vous essayez de déterminer si x est vraiment un objet de type J lorsque le programme est en cours d'exécution, donc il compile.

Pensez-vous que cela devrait entraîner une erreur de compilation parce que vous pensez que le compilateur ne connaît pas le type de x?

Modifier

Comme Kirk Woll a commenté (merci Kirk Woll!), Si vous vérifiez si x est une instanceof une classe concrète, et le compilateur peut déterminer le type de x, vous obtiendrez une erreur au moment de la compilation.

De la spécification du langage Java:

Si une distribution du RelationalExpression au referenceType serait rejetée comme une erreur de compilation, l'expression relationnelle instanceof produit également une erreur de compilation. Dans une telle situation, le résultat de l'instance de l'expression ne pourrait jamais être vrai.

À titre d'exemple:

import java.io.Serializable; 
import java.io.IOException; 
import java.io.ObjectOutputStream; 
import java.io.ObjectInputStream; 

class SerializableClass implements Serializable 
{ 
    private writeObject(ObjectOutputStream out) {} 
    private readObject(ObjectInputStream in) {} 
} 

public class DerivedSerializableClass extends SerializableClass 
{ 
    public static void main(String[] args) 
    { 
     DerivedSerializableClass dsc = new DerivedSerializableClass(); 

     if (dsc instanceof DerivedSerializableClass) {} // fine 
     if (dsc instanceof Serializable) {} // fine because check is done at runtime 
     if (dsc instanceof String) {} // error because compiler knows dsc has no derivation from String in the hierarchy 

     Object o = (Object)dsc; 
     if (o instanceof DerivedSerializableClass) {} // fine because you made it Object, so runtime determination is necessary 
    } 
} 
+1

+1, et si * n'était pas * un opérateur d'exécution, que diable serait le point de celui-ci? Les instructions 'if' qui l'utilisent n'auraient aucun sens. –

+0

Eh bien d'après ce que j'ai lu, il y a une vérification initiale de la compilation lors de l'utilisation de l'opérateur instanceof qui détermine si la source et la destination ont une relation sous-type-supertype. Ensuite, l'objet réel de la source est utilisé pour déterminer si la source est un sous-type de type Destination. – user439526

+1

S'il vous plaît corriger ma compréhension sur la façon dont cela devrait fonctionner. Donc dans ce code bien que l'objet référé par x est un sous-type de J mais il n'y a pas de relation entre I et J. Donc puisque x est de type I dans le code ci-dessus ie I x = new D(); un rôle à la compilation? – user439526

2

instanceof est un opérateur d'exécution, pas de compilation, il est donc en cours d'évaluation en utilisant le type réel de l'objet référencé.

+0

Mais il peut produire des erreurs de compilation. .. – EJP

+0

Ouais, si elle reçoit une entrée statique (ie des classes plutôt que des références). Je devrais éditer ma réponse, bien que kuropenguin ait déjà donné une réponse très exhaustive, donc c'est discutable. – EboMike

Questions connexes