Si j'essaye de lancer un String
vers un java.util.Date
, le compilateur Java intercepte l'erreur. Alors pourquoi le compilateur ne signale-t-il pas ce qui suit comme une erreur?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Bien sûr, la JVM lance un ClassCastException
à l'exécution, mais le compilateur ne le marque pas.
Le comportement est le même avec javac 1.8.0_212 et 11.0.2.
java
casting
compiler-errors
javac
Mike Woinoski
la source
la source
List
ici.Date d = (Date) new Object();
strList
s'agissait d'une instance d'une classe qui implémente List.Réponses:
Le casting est techniquement possible. Il n'est pas facile de prouver par javac que ce n'est pas le cas dans votre cas et le JLS le définit en fait comme un programme Java valide, donc signaler une erreur serait incorrect.
C'est parce que
List
c'est une interface. Donc, vous pourriez avoir une sous-classe d'unDate
qui implémente réellementList
déguisé commeList
ici - et le lancerDate
serait parfaitement correct. Par exemple:Et alors:
La détection d'un tel scénario n'est pas toujours possible, car elle nécessiterait des informations d'exécution si l'instance provient, par exemple, d'une méthode à la place. Et même si cela nécessiterait beaucoup plus d'efforts pour le compilateur. Le compilateur empêche uniquement les transtypages qui sont absolument impossibles car il n'y a aucun moyen pour l'arbre de classe de correspondre du tout. Ce qui n'est pas le cas ici, comme on le voit.
Notez que le JLS requiert que votre code soit un programme Java valide. Au 5.1.6.1. Conversion de référence restreinte autorisée, il est dit:
Ainsi, même si le compilateur peut comprendre que votre cas est réellement impossible, il n'est pas autorisé de signaler une erreur car le JLS le définit comme un programme Java valide.
Il serait seulement permis d'afficher un avertissement.
la source
myDate = (Date) myString
échouer. En utilisant la terminologie JLS, l'instruction tente de convertirS
(leString
) enT
(leDate
). Ici, ceS
n'est pas un type d'interface, donc la condition JLS citée ci-dessus ne s'applique pas. Par exemple, essayez de convertir un calendrier en une date et vous obtiendrez une erreur de compilation même si aucune des classes n'est définitive.Date & List
est inhabitable , il ne suffit pas de prouver qu'il est inhabité actuellement (il pourrait l'être à l'avenir).Considérons une généralisation de votre exemple:
Ce sont les principales raisons pour lesquelles ce
Date d = (Date) strList;
n'est pas une erreur de compilation.La raison intuitive est que le compilateur ne connaît pas (en général) le type précis de l'objet renvoyé par cet appel de méthode. Il est possible qu'en plus d'être une classe qui implémente
List
, c'est aussi une sous-classe deDate
.La raison technique est que la spécification de langage Java "autorise" la conversion de référence de rétrécissement qui correspond à ce type de conversion . Selon JLS 5.1.6.1 :
Dans un autre endroit, JLS indique également qu'une exception peut être levée lors de l'exécution ...
Notez que la détermination JLS 5.1.6.1 est basée uniquement sur les types déclarés des variables impliquées plutôt que sur les types d'exécution réels. Dans le cas général, le compilateur ne connaît pas et ne peut pas connaître les types d'exécution réels.
Alors, pourquoi le compilateur Java ne peut-il pas comprendre que la distribution ne fonctionnera pas?
Dans mon exemple, l'
someMethod
appel pourrait renvoyer des objets avec une variété de types. Même si le compilateur a pu analyser le corps de la méthode et déterminer l'ensemble précis de types pouvant être renvoyés, rien n'empêche quelqu'un de le modifier pour renvoyer différents types ... après avoir compilé le code qui l'appelle. C'est la raison fondamentale pour laquelle JLS 5.1.6.1 dit ce qu'il dit.Dans votre exemple, un compilateur intelligent pourrait comprendre que la conversion ne peut jamais réussir. Et il est autorisé d'émettre un avertissement au moment de la compilation pour signaler le problème.
Alors, pourquoi un compilateur intelligent n'est-il pas autorisé à dire que c'est une erreur de toute façon?
Parce que le JLS dit que c'est un programme valide. Période. Tout compilateur qui a appelé cela une erreur ne serait pas compatible Java.
En outre, tout compilateur qui rejette les programmes Java que le JLS et les autres compilateurs disent être valides, constitue un obstacle à la portabilité du code source Java.
la source
5.5.1. Type de référence Coulée:
List<String>
estS
etDate
estT
dans votre cas.la source