Ottima domanda!
(Nei seguenti osservazioni, wrt una classe generica in E
come Foo<E>
, definiscono "metodo covariante" come un metodo che restituisce un E
senza avere alcun parametro utilizzando E
, e un "metodo controvariante" come l'opposto: quella che prende un parametro formale di tipo E
ma non restituisce un tipo che coinvolge E
. [la vera definizione di questi termini è più complicato, ma non importa che per ora.])
sembra che il compilatore sta cercando di legare T
a Object
nel caso di f1
, perché se lo fai
class Bar0 {
public static <T> void go(Foo< Foo< ? extends T > > f) {
// can pass a Foo<T> to a contravariant method of f;
// can use any result r of any covariant method of f,
// but can't pass T to any contravariant method of r
}
}
poi i go(f1)
opere, ma ora go(f2)
non lo fa, perché, anche se Foo<String> <: Foo< ? extends String >
, che non implica che Foo< Foo<String> > <: Foo< Foo< ? extends String > >
.
Ecco alcune modifiche che compilano sia per f1
e f2
:
class Bar1 {
public static <T> void go(Foo< ? super Foo<T> > f) {
// can't properly type the results of any covariant method of f,
// but we can pass a Foo<T> to any contravariant method of f
}
}
class Bar2 {
public static <T> void go(Foo< ? extends Foo< ? extends T > > f) {
// can't pass a Foo<T> to a contravariant method of f;
// can use result r of any covariant method of f;
// can't pass a T to a contravariant method of r;
// can use result of covariant method of r
}
}
fonte
2012-09-23 05:12:52
È bello vedere esempi di lavoro. – Cyker
Che dire del caso di 'Foo>'? Se ho bisogno di lavorare in termini di 'Foo >' Posso scrivere 'Foo estende Foo >> 'ma ritengo che porti più varianza che in realtà avrei intenzione di usare' Foo > '. Come accettare 'Foo ' come 'Foo >' è chiamato in termini di varianza? –
ony
Se capisco la tua domanda @ony, non accetto affatto. 'Foo>' non è un 'Foo < Foo< ? >>'.In generale, 'G < S >' non è un 'G < T >' anche se 'S' è un' T', ma 'G < S >' è un 'G estende T> 'e' G < T > 'è un' G < ? super S > '. 'Foo < ? >' è l'abbreviazione di 'Foo estende Object> ', quindi' Foo < String > 'è un' Foo < ? > '. Ma lasciamo che 'Foo < String >' sia 'S' e' Foo < ? > 'sia' T'. La non-relazione sopra significa 'Foo < S >' non è un 'Foo < T >'. –