Comprensione della parola chiave generica JAVA 'super'

7

Recentemente alcune persone hanno affermato di aver sbagliato quando ho spiegato perché non è possibile inserire un oggetto Number in una lista dichiarata come List<? super RationalNumber> . (Ciò presuppone che RationalNumber sia una sottoclasse di Number )

La mia spiegazione era che in List<? super RationalNumber> il <? super RationalNumber> rappresenta una super classe sconosciuta di RationalNumber . Ciò significa che <? super RationalNumber> indica che un oggetto valido per List<? super RationalNumber> è un oggetto che estende una super classe sconosciuta di RationalNumber .

Poiché una super classe sconosciuta di RationalNumber è davvero sconosciuta (ad esempio può essere un'interfaccia X invece di Number ), non è garantito che Number sia una sottoclasse di X ie implementa X , quindi Number non è una sostituzione valida di <? super RationalNumber> .

Cosa c'è di sbagliato in questa spiegazione? Edit: Nota che ti sto chiedendo cosa non va nel modo in cui spiego, la mia spiegazione. Non un'altra spiegazione per la domanda originale.

Grazie.

    
posta InformedA 04.07.2014 - 08:39
fonte

2 risposte

7

List<? super RationalNumber> è una lista di qualche tipo X che è una superclasse di RationalNumber. La tua ipotesi è che RationalNumber sia una sottoclasse di Number , quindi i possibili candidati per X sono RationalNumber , Number o Object . La possibilità più restrittiva è che X sia RationalNumber stesso. Un List<RationalNumber> può contenere solo istanze di RationalNumber e non può contenere istanze di Number .

In breve, una List<? super T> è una lista che può accettare istanze di T, ma i contenuti correnti sono di tipo sconosciuto. Questo contrasta con List<? extends T> , che contiene istanze di T, ma non consente di aggiungere nuovi elementi perché il tipo accettato è sconosciuto.

Questo esempio illustra l'uso di super :

void storePies(List<? super RationalNumber> list) { 
    list.add(new RationalNumber(22, 7))
    list.add(new RationalNumber(355, 113))
}

...
List<Number> list = new ArrayList<Number>();
storePies(list);
list.add(3.14159265358979);

Questo esempio illustra l'uso di extends :

double sum(Collection<? extends Number> numbers) {
    double s = 0;
    for (Number n: numbers) { s += n.doubleValue(); }
    return s;
}

List<Integer> somePrimes = new ArrayList<Integer>();
somePrimes.add(5);
somePrimes.add(17);
double total = sum(somePrimes);
    
risposta data 04.07.2014 - 09:08
fonte
5

Vedi anche:

Una digressione. Sentiti libero di saltare.

Per i programmatori che hanno familiarità con C #, esiste una funzionalità simile:

I termini, covarianza e controvarianza, possono essere ricondotti alle prime discussioni provenienti dal principio di sostituzione di Liskov (LSP) .

L'obiettivo di progettazione del carattere jolly con limite inferiore (LBWC) è quello di garantire la sicurezza del tipo della seguente parte di codice.

(Questo è solo un esempio, uno degli esempi molto semplici tra gli altri.)

List<? super RationalNumber> containerOne = new ArrayList<RationalNumber>(); 
List<? super RationalNumber> containerTwo = new ArrayList<Number>(); 
List<? super RationalNumber> containerThree = new ArrayList<Object>(); 

RationalNumber itemValue = new RationalNumber(22, 7); 

containerOne.add(itemValue); 
containerTwo.add(itemValue); 
containerThree.add(itemValue);

In breve, LBWC consente al "handle" - classi generiche con un LBWC ( containerOne , containerTwo , containerThree nel campione sopra) a :

  • Essere assegnate alle istanze della classe generica (del parametro type T ) ogni volta che è noto che RationalNumber può essere tranquillamente convertito in T .

Ora, usiamo questa conoscenza e proviamo a rispondere alla domanda: possiamo passare un Number a un tale "handle" - una classe generica con un LBWC di RationalNumber ?

Dato che

  • È valido assegnare un'istanza di new List<RationalNumber>() a un handle di List<? super RationalNumber> varGeneric .
  • Naturalmente è valido fare qualcosa di completamente diverso; ma il design di LBWC è che questa è la la situazione di cui ha bisogno di occuparsi.

Otteniamo questa domanda correlata:

  • Possiamo chiamare new List<RationalNumber>().add(new Number(...)) ?
    • Certo che no.

Visto che l'obiettivo di progettazione di LBWC è impedire che ciò accada, si può trarre questa conclusione:

  • Se LBWC è progettato per essere applicabile a tutti (dal compilatore o dalla polizia linguistica), deve impedire questo incarico (inserendo Number per un tipo ? per il quale LBWC è RationalNumber ) da accadendo.

Questo risponde alla domanda dal punto di vista del design. La questione dell'applicazione può essere risolta solo dai membri senior della comunità che hanno familiarità con la costruzione del linguaggio Java e dei suoi strumenti di compilazione. I commenti della folla generale forniranno solo speculazioni, o "ipotesi" o "teorie".

    
risposta data 04.07.2014 - 09:54
fonte

Leggi altre domande sui tag