Si prega di mostrare un buon esempio di covarianza e controvarianza in Java.Dimostrare covarianza e controvarianza in Java?
risposta
covarianza:
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub # getSomething è covariante perché restituisce una sottoclasse del tipo di ritorno di Super # getSomething (ma capace di soddisfare qualunque contratto di Super.getSomething())
controvarianza
class Super{
void doSomething(String parameter)
}
class Sub extends Super{
void doSomething(Object parameter)
}
Sub # doSomething è contrava Riant perché prende un parametro di una superclasse del parametro di Super # doSomething (ma, ancora una volta, completa il contratto di Super # doSomething)
Avviso: questo esempio non funziona in Java. Il compilatore Java potrebbe sovraccaricare e non sovrascrivere il metodo doSomething(). Altre lingue supportano questo stile di contravarianza.
Generics
Ciò è possibile anche per i medicinali generici:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
È ora possibile accedere a tutti i metodi di covariantList
che non ci vuole un parametro generico (come deve essere qualcosa "extends Object"), ma i getter funzioneranno correttamente (poiché l'oggetto restituito sarà sempre di tipo "Object")
L'opposto è vero per contravariantList
: È possibile accedere a tutti i metodi con parametri generici (si sa che deve essere una superclasse di "String", in modo che si possa sempre passare uno), ma nessun getter (il tipo restituito può essere di qualsiasi altro supertipo di stringa)
Vedere Liskov substitution principle. In effetti, se la classe B estende la classe A, dovresti essere in grado di usare una B ogni volta che è richiesta una A.
Questo non risponde alla domanda ed è fuorviante. Sarebbe del tutto possibile progettare un sistema variante che infrange la correttezza semantica e quindi viola LSP. –
questo non è il caso di "contr Variante". 'super.doSomething (" String ")' non può essere sostituito da 'sub.doSomething (Object)'. – zinking
Co-varianza: Iterable e Iterator. È quasi sempre utile definire una co-variante Iterable
o Iterator
. Iterator<? extends T>
può essere utilizzato solo come Iterator<T>
- l'unico posto in cui viene visualizzato il parametro di tipo è il tipo restituito dal metodo next
, quindi può essere tranquillamente convertito in T
. Ma se hai S
estende T
, puoi anche assegnare Iterator<S>
a una variabile di tipo Iterator<? extends T>
. Per esempio, se si sta definendo un metodo find:
boolean find(Iterable<Object> where, Object what)
non sarà in grado di chiamare con List<Integer>
e 5
, quindi è meglio definito come
boolean find(Iterable<?> where, Object what)
Contra-varianza: comparatore. È quasi sempre logico utilizzare Comparator<? super T>
, perché può essere utilizzato solo come Comparator<T>
. Il parametro type appare solo come il tipo di parametro del metodo compare
, quindi è possibile passare in modo sicuro a T
.Per esempio, se si dispone di un DateComparator implements Comparator<java.util.Date> { ... }
e si desidera ordinare un List<java.sql.Date>
con quello di confronto (java.sql.Date
è una sotto-classe di java.util.Date
), si può fare con:
<T> void sort(List<T> what, Comparator<? super T> how)
ma non con
<T> void sort(List<T> what, Comparator<T> how)
Il primo esempio di controvarianza non funziona in Java. doSomething() nella classe Sub è un overload, non un override. –
Infatti. Java non supporta gli argomenti controvarianti in sottotipizzazione. Solo covarianza per ciò che riguarda i tipi di ritorno del metodo (come nel primo esempio). –
Ottima risposta. La covarianza mi sembra logica. Ma potresti indicarmi un paragrafo in JLS che descrive la contravarianza? Perché viene richiamato Sub.doSomething? – Mikhail