Fornire esempi di funzioni che dimostrano covarianza e controvarianza nei casi sia di sovraccarico che di sovrascrittura in Java? [chiuso]


Risposte:


155

covarianza:

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

Sub # getSomething è covariante perché restituisce una sottoclasse 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 superclasse del parametro di Super # doSomething (ma, di nuovo, soddisfa il contratto di Super # doSomething)

Avviso: questo esempio non funziona in Java. Il compilatore Java sovraccaricherà e non sovrascriverà il metodo doSomething (). Altre lingue supportano questo stile di controvarianza.

Generics

Questo è possibile anche per i generici:

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

Ora puoi accedere a tutti i metodi covariantListche non richiedono un parametro generico (poiché deve essere qualcosa che "estende Object"), ma i getter funzioneranno bene (poiché l'oggetto restituito sarà sempre di tipo "Object")

È vero il contrario per contravariantList: puoi accedere a tutti i metodi con parametri generici (sai che deve essere una superclasse di "String", quindi puoi sempre passarne uno), ma nessun getter (il tipo restituito può essere di qualsiasi altro supertipo di String )


79
Il primo esempio di controvarianza non funziona in Java. doSomething () nella classe Sub è un sovraccarico, non un override.
Craig P. Motlin

15
Infatti. Java non supporta argomenti controvarianti nella sottotipizzazione. Solo covarianza per ciò che riguarda i tipi restituiti dal metodo (come nel primo esempio).
the_dark_destructor

Bella risposta. La covarianza mi sembra logica. Ma potresti indicarmi un paragrafo in JLS che descrive la controvarianza? Perché viene invocato Sub.doSomething?
Mikhail

2
Come ha sottolineato Craig, non lo è. Penso che qui ci sia uno scontro tra override e sovraccarico e SUN ha scelto (come sempre) l'opzione compatibile con le versioni precedenti. Quindi in Java non è possibile utilizzare parametri controvarianti quando si sovrascrive un metodo.
Hardcoded

1
Sarebbe bello sapere perché ottengo voti negativi per la mia risposta.
Hardcoded

48

Co-varianza: iterabile e iteratore. Ha quasi sempre senso definire una co-variante Iterableo Iterator. Iterator<? extends T>può essere usato proprio come Iterator<T>- l'unico posto in cui appare il parametro type è il tipo restituito dal nextmetodo, quindi può essere tranquillamente convertito T. Ma se hai Sestensioni T, puoi anche assegnarle Iterator<S>a una variabile di tipo Iterator<? extends T>. Ad esempio, se stai definendo un metodo di ricerca:

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

non potrai chiamarlo con List<Integer>e 5, quindi è meglio definito come

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

Controvarianza: comparatore. Ha quasi sempre senso da usare Comparator<? super T>, perché può essere usato proprio come Comparator<T>. Il parametro type viene visualizzato solo come tipo di parametro del comparemetodo, quindi Tpuò essere passato in sicurezza ad esso. Ad esempio, se hai un DateComparator implements Comparator<java.util.Date> { ... }e vuoi ordinare un List<java.sql.Date>con quel comparatore ( java.sql.Dateè una sottoclasse di java.util.Date), puoi fare con:

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

ma non con

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

-4

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


6
Questo non risponde alla domanda ed è fuorviante. Sarebbe del tutto possibile progettare un sistema variante che infrange la correttezza semantica e quindi viola LSP.
Matt Whipple,

questo non è il caso per contra variantdire. super.doSomething("String")non può essere sostituito da sub.doSomething(Object).
Zinking

Non è il problema
OlivierTerrien
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.