La première chose à garder à l'esprit est que les opérateurs ternaires Java ont un "type", et que c'est ce que le compilateur déterminera et considérera quels que soient les types réels / réels du deuxième ou du troisième paramètre. En fonction de plusieurs facteurs, le type d'opérateur ternaire est déterminé de différentes manières, comme illustré dans la spécification du langage Java 15.26
Dans la question ci-dessus, nous devrions considérer le dernier cas:
Sinon, les deuxième et troisième opérandes sont respectivement de types S1 et S2 . Soit T1 le type qui résulte de l'application de la conversion de boxe à S1 , et soit T2 le type qui résulte de l'application de la conversion de boxe à S2 . Le type de l'expression conditionnelle est le résultat de l'application de la conversion de capture (§5.1.10) en lub (T1, T2) (§15.12.2.7).
C'est de loin le cas le plus complexe une fois que vous regardez l' application de la conversion de capture (§5.1.10) et surtout à lub (T1, T2) .
En anglais simple et après une simplification extrême, nous pouvons décrire le processus comme le calcul de la "Superclasse la moins commune" (oui, pensez au LCM) des deuxième et troisième paramètres. Cela nous donnera l'opérateur ternaire "type". Encore une fois, ce que je viens de dire est une simplification extrême (considérez les classes qui implémentent plusieurs interfaces communes).
Par exemple, si vous essayez ce qui suit:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
Vous remarquerez que le type résultant de l'expression conditionnelle est java.util.Date
puisqu'il s'agit de la "Superclasse la moins commune" pour la paire Timestamp
/ Time
.
Puisqu'il null
peut être autoboxé à n'importe quoi, la "Superclasse la moins commune" est la Integer
classe et ce sera le type de retour de l'expression conditionnelle (opérateur ternaire) ci-dessus. La valeur de retour sera alors un pointeur nul de type Integer
et c'est ce qui sera retourné par l'opérateur ternaire.
Au moment de l'exécution, lorsque la machine virtuelle Java déballe, le Integer
a NullPointerException
est lancé. Cela se produit car la machine virtuelle Java tente d'appeler la fonction null.intValue()
, où null
est le résultat de la détection automatique.
À mon avis (et comme mon avis n'est pas dans la spécification du langage Java, beaucoup de gens trouveront cela faux de toute façon), le compilateur fait un mauvais travail en évaluant l'expression dans votre question. Étant donné que vous avez écrit, true ? param1 : param2
le compilateur doit déterminer tout de suite que le premier paramètre - null
- sera renvoyé et il doit générer une erreur de compilation. C'est un peu similaire à lorsque vous écrivez while(true){} etc...
et que le compilateur se plaint du code sous la boucle et le marque avec Unreachable Statements
.
Votre deuxième cas est assez simple et cette réponse est déjà trop longue ...;)
CORRECTION:
Après une autre analyse, je crois que j'avais tort de dire qu'une null
valeur peut être encadrée / auto-indexée sur n'importe quoi. En parlant de la classe Integer, la boxe explicite consiste à invoquer le new Integer(...)
constructeur ou peut-être le Integer.valueOf(int i);
(j'ai trouvé cette version quelque part). Le premier lancerait un NumberFormatException
(et cela n'arrive pas) tandis que le second n'aurait tout simplement pas de sens car un int
ne peut pas être null
...
int foo = (true ? null : 0)
et lesnew Integer(null)
deux se compilent bien, le second étant la forme explicite de la boîte automatique.