Perché non posso fare riferimento a un'interfaccia all'interno di parentesi generiche in una dichiarazione di variabile?

5

Ho provato a scrivere quanto segue:

public class AdjacencyList<Vertex> {

    Map<Vertex, Set<Edge<Vertex>>> adj = new HashMap<Vertex, HashSet<Edge<Vertex>>>();
}

Ma ho ricevuto l'errore:

Type mismatch: cannot convert from HashMap<Vertex,HashSet<Edge<Vertex>>> to Map<Vertex,Set<Edge<Vertex>>>

Eclipse vuole che cambi la linea in:

Map<Vertex, HashSet<Edge<Vertex>>> adj = new HashMap<Vertex, HashSet<Edge<Vertex>>>();

(nota che sta specificando il tipo di Set a sinistra.

Sto cercando di prendere l'abitudine di specificare le interfacce invece dei tipi esatti. Perché non mi lascia in questo caso?

    
posta Carcigenicate 12.07.2015 - 21:26
fonte

2 risposte

8

Credo che a meno che specificatamente specificato, i generici in Java siano invarianti , ovvero che (per semplificare), List<string> non erediti da List<Object> , anche se String eredita% codice%. Considera che un Object ha un metodo List<Object> , che, se è stato ereditato da add(Object o) , può essere usato per aggiungere non-stringhe all'elenco e rompere il tipo stesso di sicurezza che i generici sono qui a fornirci. Allo stesso modo, List<String> non è la classe base di Map<Vertex,Set<...>> , anche se Map<Vertex, HashSet<...>> è di Set .

Prova a leggere questo articolo su Covariance and Contravariance in Java, che spiega questo problema in termini generali e mostra come utilizzare i limiti generici per estendere i possibili argomenti generici di un tipo:

Unbounded wildcards allow assignment with any type parameter:

List<?> list = new ArrayList<Clazz>();

Bounded wildcards affect assignment like you might expect:

List<? extends Clazz> list = new ArrayList<SubClazz>();
List<? super Clazz> list2 = new ArrayList<Object>();
    
risposta data 12.07.2015 - 21:45
fonte
1

Crea ciò che stai istanziando in concreto ( HashMap ), ma mantieni il tipo generico astratto. Qualcosa come:

Map<Vertex, Set<Edge<Vertex>>> adj = new HashMap<Vertex, Set<Edge<Vertex>>>();

adj.put(new Vertex(), new HashSet<Edge<Vertex>>());

Tieni presente che questo consentirà di utilizzare altri tipi di Set come valori in Map , che può essere o non essere ciò che intendi. Se vuoi solo HashSet s in Map , il suggerimento di Eclipse sarebbe la strada da percorrere.

    
risposta data 12.07.2015 - 21:38
fonte

Leggi altre domande sui tag