Se un programmatore desidera eseguire il cast esplicito di un tipo X
per digitare Y
, il linguaggio potrebbe semplicemente consentirlo, assumendo che il programmatore conosca meglio del compilatore.
Ma i bravi ragazzi di Java vogliono evitare alcuni cast ovviamente impossibili, ad es. (Cat)dog
. Quindi hanno questa sezione dettagliata gloriosa dedicata al tema - http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
Ma, ci sono problemi con queste regole? E i compilatori sono conformi a queste regole? ... Queste domande sono troppo complesse e non molto interessanti.
Quello che dovremmo preoccuparci è se il cast ha senso; se ha senso, e il compilatore si rifiuta di accettarlo, nessun problema, basta aggirarlo.
Nella tua domanda, ci sono due posti per inserire i caratteri jolly, in Foo< >
, e in Iterable< >
. In ogni luogo, il carattere jolly può essere
0. None
1. Bounded "? extends Something"
2. Unbounded "?"
quindi cerchiamo di esplorare tutte le combinazioni, ed ecco la mia conclusione:
wildcard#1 wildcard#2 should_compile javac eclipse
00 - - Y Y N
01 - ? extends N N N
02 - ? N N N
10 ? extends - Y N Y
11 ? extends ? extends Y N Y
12 ? extends ? Y Y Y
20 ? - Y Y Y
should_compile
significa il cast ha un senso o no, ha spiegato in seguito.
Nel caso 10 and 11
, il codice deve essere compilato, ma javac lo rifiuta. O le regole hanno problemi, o javac ha dei bug.
Vediamo, ad esempio, il motivo per caso 00
ha senso e dovrebbe compilare
void test00(Foo<Iterable<String>> foo) {
Bar<?> bar = (Bar<?>) foo;
}
the question is, could there be a class/interface `X`, such that
Bar<X> <: Foo<Iterable<String>>
=> Foo<Iterable<X>> <: Foo<Iterable<String>>
=> Iterable<X> = Iterable<String>
=> X = String
so the answer is yes, the cast makes sense.
e perché caso 01
non dovrebbe compilare
Foo<Iterable<X>> <: Foo<Iterable<? extends String>>
=> Iterable<X> = Iterable<? extends String>
=> NO SOLUTION
note that Iterable<String> != Iterable<? extends String>
e caso 11
Foo<Iterable<X>> <: Foo<? extends Iterable<? extends String>>
=> Iterable<X> <: Iterable<? extends String>
=> X <: String
È sorprendente che il caso 01
non debba essere compilato, sebbene sia sensato. Il problema principale è, Iterable
è convocante, e dovremmo usare un carattere jolly con esso quasi ovunque sia usato. Quindi idealmente dovremmo dichiarare
class Bar<T> implements Foo<Iterable<? extends T>>
ma la vita è un inferno se inseriamo caratteri jolly ovunque. La soluzione migliore è la variazione del sito di dichiarazione. Non sono sicuro che Java aggiungerà mai questa funzionalità prima che tutti andiamo in pensione.
Speriamo che tu non debba mai fare un brutto casting così e questa è solo una domanda di curiosità ... – jahroy
Sì, solo curiosità. L'esempio di vita reale era in realtà un'istanza di controllo in cui "instanceof Bar" funzionava ma "instanceof Bar >" no. –
C'è qualche menzione qui, http://docs.oracle.com/javase/tutorial/java/generics/capture.html –