ProgrammazioneSviluppatore Backend

Parlate dei principali aspetti del lavoro con la generazione e l'uso dei generics in Java, quali dettagli è importante conoscere per un'applicazione sicura?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

I generics permettono di creare classi, interfacce e metodi con parametri di tipo, il che garantisce il controllo del tipo in fase di compilazione e aiuta a evitare ClassCastException.

Caratteristiche chiave e insidie:

  • Type Erasure: In fase di compilazione, le informazioni sui parametri di tipo vengono annullate, quindi non è possibile, ad esempio, creare un array di tipo generico: new List<String>[10] — errore di compilazione.
  • Limitazioni all'uso:
    • Non è possibile creare istanze di un tipo parametrizzato: T obj = new T();
    • Non è possibile utilizzare instanceof con tipi parametrizzati: if(obj instanceof List<String>) — errore.
    • Non è possibile creare campi statici di tipi parametrizzati.
  • Wildcards: ? extends T — covarianza (lettura), ? super T — controvarianza (scrittura).
  • Principio PECS (Producer Extends, Consumer Super): Se è necessario solo leggere — utilizzare extends, se scrivere — super.

Esempio:

// Approccio covariante per la lettura void printNumbers(List<? extends Number> numbers) { for (Number n : numbers) { System.out.println(n); } } // Approccio controviante per la scrittura void addIntegers(List<? super Integer> list) { list.add(10); } }

Domanda ingannevole.

Domanda: "Qual è la differenza tra List<Object> e List<?>? È possibile inserire qualsiasi oggetto in List<?>?"

Risposta: No, in List<?> non è possibile aggiungere nulla (tranne null), perché il compilatore non sa quale parametro di tipo ci sia esattamente. In List<Object> è possibile aggiungere qualsiasi oggetto.

Esempio:

List<?> list1 = new ArrayList<String>(); // list1.add("test"); // Errore di compilazione! List<Object> list2 = new ArrayList<>(); list2.add("test"); // OK

Esempi di errori reali a causa della mancanza di conoscenza delle complessità del tema.


Storia

Un team di sviluppatori ha tentato di implementare una cache basata su un array di tipo parametrizzato T[]. A causa del type erasure e dell'impossibilità di creare array di tipo generico, la soluzione non ha funzionato come previsto: si otteneva un array Object[], che portava a ClassCastException durante i cast a runtime.


Storia

In uno dei microservizi, uno sviluppatore ha tentato di implementare un receiver utilizzando List<?> come parametro, e ha cercato di modificare la collezione. Questo ha causato un errore di compilazione e ha ritardato la release, poiché è stato necessario rifattorizzare la logica tenendo conto del PECS.


Storia

Nel progetto di integrazione con un sistema esterno, uno sviluppatore ha commesso un errore sovrascrivendo una collezione di un tipo con un'altra tramite un raw-type non gestito: List list = new ArrayList<String>(), il che ha portato a ClassCastException e crash del servizio in produzione durante il tentativo di castare gli elementi a altri tipi.