Dimostrare covarianza e controvarianza in Java?

Si prega di mostrare un buon esempio di covarianza e controvarianza in Java.

covarianza:

class Super { Object getSomething(){} } class Sub extends Super { String getSomething() {} } 

Sub # getSomething è covariante perché restituisce una sottoclass del tipo restituito di Super # getSomething (ma completa il contratto di Super.getSomething ())

controvarianza

 class Super{ void doSomething(String parameter) } class Sub extends Super{ void doSomething(Object parameter) } 

Sub # doSomething è controvariante perché prende un parametro di una superclass del parametro di Super # doSomething (ma, ancora una volta, compila 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

Questo è anche ansible per Generics:

 List aList... List< ? extends Object> covariantList = aList; List< ? super String> contravariantList = aList; 

Ora puoi accedere a tutti i metodi di covariantList che non accettano un parametro generico (poiché deve essere qualcosa “extends Object”), ma i getter funzioneranno correttamente (poiché l’object restituito sarà sempre di tipo “Object”)

L’opposto è vero per contravariantList : puoi accedere a tutti i metodi con parametri generici (sai che deve essere una superclass di “String”, quindi puoi sempre passarne uno), ma non getter (il tipo restituito può essere di qualsiasi altro supertipo di Stringa)

Co-varianza: Iterable e Iterator. È quasi sempre sensato definire una co-variante Iterable o Iterator . Iterator< ? extends T> Iterator< ? extends T> può essere usato proprio come Iterator – l’unico posto in cui appare il parametro type è il tipo restituito dal metodo next , quindi può essere tranquillamente trasmesso su T Ma se hai S estende T , puoi anche assegnare Iterator a una variabile di tipo Iterator< ? extends T> Iterator< ? extends T> . Ad esempio se stai definendo un metodo di ricerca:

 boolean find(Iterable where, Object what) 

non sarai in grado di chiamarlo con List e 5 , quindi è meglio definito come

 boolean find(Iterable< ?> where, Object what) 

Contro-varianza: comparatore. Ha quasi sempre senso usare Comparator< ? super T> Comparator< ? super T> , perché può essere usato solo come Comparator . Il parametro type appare solo come il tipo di parametro del metodo di compare , quindi T può essere tranquillamente passato ad esso. Ad esempio, se hai un DateComparator implements Comparator { ... } e vuoi ordinare una List con quel comparatore ( java.sql.Date è una sottoclass di java.util.Date ), puoi fare con:

  void sort(List what, Comparator< ? super T> how) 

ma non con

  void sort(List what, Comparator how) 

Guarda il principio di sostituzione di Liskov . In effetti, se la class B estende la class A, dovresti essere in grado di usare una B ogni volta che è richiesta una A.