Introduzione

Il simbolo ? è uno strumento che rendere i tipi generici più flessibili.

Può essere utilizzato al posto del nome di un tipo generico come segnaposto, in particolare si utilizza quando non è necessario conoscere il tipo parametrico da dare in input ad un oggetto di una classe con tipo generico.

ArrayList<?> lista = new ArrayList<String>();

Limiti

  • No tipo di ritorno: non può essere utilizzato come tipo di ritorno di un metodo.
  • No parametro di un costruttore: non può essere utilizzato come tipo di parametro di un costruttore.

Esempi Approfonditi

Utilizzo dell’operatore wildcard con una classe generica:

`ArrayList<?> lista = new ArrayList<String>();
 
lista.add("Ciao"); // Errore di compilazione
lista.toString();  // Si può fare  
 
for (Object elemento : lista) { // Si può fare
       System.out.println(elemento);
}

Utilizzo dell’operatore wildcard con un metodo

`public void stampaLista(List<?> lista) {
  lista.add("Ciao"); // Errore di compilazione
  lista.toString();  // Si può fare  
   
  for (Object elemento : lista) {
       System.out.println(elemento);
   }
}

In questi esempi è possibile fare operazioni che non dipendono dal tipo della lista, ad esempio operazioni di lettura come to string, o un ciclo su gli elementi

Non è possibile aggiungere un elemento alla lista, si ottiene un errore di compilazione, poiché il tipo di lista è sconosciuto e non si può garantire che l’elemento aggiuntivo sia del tipo corretto.

È possibile risolvere questo problema limitando il tipo di dati che può essere utilizzato attraverso extends.

Extends e Super

Il ? extends e ? super sono un modi per limitare il tipo di dati che può essere utilizzato con l’operatore jolly ? e sono utilizzati con la convenzione PECS.

Quando si utilizza ? extends, si specifica che il tipo di dati deve essere una sotto-classe di un tipo specifico.

Quando si utilizza ? super, si specifica che il tipo di dati deve essere una super-classe di un tipo specifico.

List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Integer>();
List<? extends Number> c = new ArrayList<Double>();
List<? super Integer> x = new ArrayList<Number>();
List<? super Integer> y = new ArrayList<Integer>();
List<? super Integer> z = new ArrayList<Object>();

Esempio Approfondito

`List<? super Integer> lista = new ArrayList<Number>();
lista.add(10); // Ok

In questo esempio, l’operatore jolly ? è utilizzato con un limite superiore super Integer, il che significa che la lista può contenere solo elementi di tipo Integer o suoi supertipi. In questo caso, l’aggiunta di un elemento alla lista è consentita, poiché il tipo di lista è compatibile con il tipo dell’elemento aggiunto.