expliquer cette sortie sur la conversion de référence d’object?

interface I { } class A { } class B { } public class Test { public static void main(Ssortingng args[]) { A a = null; B b = (B)a; // error: inconvertible types I i = null; B b1 = (B)i; } } 

Je sais pourquoi a ne peut pas être converti en B , car B n’hérite pas de A
Ma question concerne pourquoi B b1 = (B)i; est autorisé puisque B n’est pas implémenté par I ?
et pourquoi B b1 = (B)i; cette ligne ne forcera pas une exception d’exécution puisque i est null?

Le compilateur ne sait pas tout sur votre hiérarchie de classes. En ce qui concerne cela, il pourrait y avoir class B2 extends B implements I , auquel cas la dissortingbution ci-dessus devrait fonctionner.

Lorsque le compilateur rencontre B b = (B)a; il sait sans aucun doute que a est de type A et qu’il n’est pas légalement converti en B

Cependant, lorsque le compilateur est en train de comstackr B b1 = (B)i; il sait seulement que i un object qui implémente I – cela pourrait être:

 class C extends B implements I { } 

et donc le casting sur B pourrait être légal afin qu’il ne puisse pas le traiter comme une erreur.

Il s’agit en réalité d’une simple reformulation de la réponse de Jaffrey avec un peu plus de récit.

c’est une conversion de référence étroite .. conformément à la spécification Java 5.1.5 suivante est autorisée.

De n’importe quel type d’interface J à n’importe quel type de classe C non paramétré qui n’est pas final.

cette conversion ne montrera aucune erreur de compilation mais sera vérifiée au moment de l’exécution. il ClassCastException une ClassCastException selon $ 5.5.3 si l’interface a été initialisée avec une classe appropriée qui n’est pas liée à B. mais elle ne se lance pas maintenant car l’interface est nulle et comme nous le soaps

Une valeur du type null (la référence null est la seule valeur de ce type) peut être affectée à tout type de référence, ce qui donne une référence null de ce type.

NB .. Je n’ai pas été reconnu pour tous les termes ci-dessus … Je me sens juste intéressé à chercher après avoir vu la question. alors corrigez-moi si ma conclusion est fausse ou si je n’ai rien compris

Considérer:

 interface I { } class A { } class B { } class A2 extends A implements I { } class B2 extends B implements I { } void castToB(I i) { B b1 = (B)i; // (HERE) } void foo() { A2 a2 = new A2(); castToB(a2); // legal, since a2 implements I, but the cast to B will throw an // exception at runtime B2 b2 = new B2(); castToB(b2); // legal, since b2 implements I; the cast to B now succeeds, since // a B2 is a B } 

Cela montre pourquoi la dissortingbution dans la ligne marquée HERE doit être légale, car il existe des scénarios dans lesquels elle peut réussir. Java ne signalerait le casting comme une erreur que s’il n’y avait absolument aucun moyen de réussir.

Je crois que les autres réponses manquent un détail important: c’est possible parce que le compilateur ne se soucie tout simplement pas des interfaces.

Les arguments qui sont censés expliquer cela ont été formulés comme suit:

il pourrait y avoir class B2 extends B implements I

et

Le compilateur sait ici que A et B ne sont pas liés

Celles-ci sont très vraies, mais cela n’explique pas pourquoi le compilateur sait que ces deux classes ne sont pas liées et pourquoi il ne peut pas savoir si une interface a été implémentée.

En fin de compte, ces deux situations devraient être assez similaires: si elle peut vérifier au moment de la compilation si deux classes ont une relation, alors elle devrait pouvoir vérifier lors de la compilation si une interface est implémentée dans cette classe car ces deux situations ont leurs informations disponibles au moment de la compilation.

Par conséquent, je suis d’accord avec le commentaire de Hot Licks dans la copie :

Car. Même si Cat ne peut pas implémenter directement les meubles, certaines super-classes de Cat peuvent le faire. Et le compilateur choisit de ne pas creuser dans des détails aussi laids, car les règles pour les interfaces sont assez compliquées. (Merci, Sun.) Et il n’y a pas de règle générale imposant au compilateur de détecter une exception d’exécution inévitable (telle que la division par zéro) – il s’agit davantage d’un “service” fourni.

Vérifier l’interface au moment de la compilation devrait être possible, le compilateur ne le fait pas pour des raisons que nous ne pouvons que deviner. qui sont discutés dans les commentaires .

Après une discussion approfondie (et très intéressante) dans les commentaires ci-dessous, je pense que cela a été clarifié.

Il est facile et peu coûteux de vérifier si deux classes ont une relation, il suffit de regarder leurs deux hiérarchies. D’autre part, les interfaces nécessitent que vous connaissiez toutes les classes et les interfaces du projet (y compris les ressources externes telles que les bibliothèques) afin de déterminer s’il existe une relation entre l’interface et la classe.

Cela m’amène à la conclusion que, même si cela est théoriquement possible, ce n’est tout simplement pas réalisable car cela nécessiterait deux choses:

  1. Recomstackr votre code source et toutes les bibliothèques incluses.
  2. Chèques très coûteux qui doivent passer par les hiérarchies de chaque classe.

Voici quelques bonnes informations sur le casting Upcasting et Down. http://forum.codecall.net/topic/50451-upcasting-downcasting/

Étant donné que chaque classe hérite d’un object, vous pouvez toujours passer en mode amont vers un object et en aval pour un autre type (B)(Object)a . Ce n’est pas une bonne idée, mais c’est valable. Si vous aviez réellement instancié A, vous obtiendrez une exception d’exécution à l’exception java.lang.ClassCastException la même manière que si vous instanciez une instance de I i = new I(){}

 interface I { } class A { } class B { } class Test { public static void main(Ssortingng args[]) { A a = null; B b = (B)(Object)a; I i = null; B b1 = (B)i; } }