ProgrammazioneSviluppatore Java

Che cosa sono gli oggetti immutable in Java, quale è il loro valore e come implementare correttamente una propria classe immutable?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Oggetti Immutable — sono oggetti il cui stato non può essere modificato dopo la creazione. Le loro caratteristiche principali:

  • Tutti i campi sono finali;
  • Non contengono setter;
  • Non è possibile ottenere un riferimento mutabile agli oggetti interni (ad esempio, collezioni).

Vantaggi degli oggetti immutable:

  • Sicuri per l'accesso multithread (thread-safe);
  • Facili da memorizzare nella cache e riutilizzare come chiavi nelle collezioni;
  • Semplificano il debug e i test;
  • Meno bug a causa di modifiche inattese allo stato.

Esempio di implementazione di una classe immutable:

public final class Person { private final String name; private final int age; private final List<String> phones; public Person(String name, int age, List<String> phones) { this.name = name; this.age = age; // Protezione contro la mutazione della lista passata this.phones = Collections.unmodifiableList(new ArrayList<>(phones)); } public String getName() { return name; } public int getAge() { return age; } public List<String> getPhones() { return phones; } // Restituiamo una lista di sola lettura }

Domanda insidiosa.

Perché String in Java è immutable e cosa succederebbe se non lo fosse? Molti rispondono "per sicurezza", ma cosa significa questo nella pratica?

Risposta:

String è utilizzato in molti posti: come chiavi nelle collezioni, nella logica di sicurezza (ad esempio, le password). Se la stringa potesse essere cambiata tramite un singolo riferimento, ciò influenzerebbe tutti gli altri riferimenti allo stesso oggetto, il che renderebbe impossibile il corretto funzionamento delle collezioni (ad esempio, HashMap — durante il calcolo dell'hashCode) e potrebbe portare a vulnerabilità di sicurezza.

Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze dell'argomento.


Storia

In un grande progetto bancario, venivano passate collezioni interne (lista delle transazioni) attraverso un normale getter. Di conseguenza, la lista poteva essere modificata dall'esterno, violando gli invarianti (ad esempio, aggiungendo una transazione con una data non valida). Questo ha portato a perdita di dati, fino a quando non sono stati restituiti Collections.unmodifiableList.

Storia

Nella classe root della configurazione erano presenti oggetti-campo non protetti (Date, List). In un thread la configurazione è stata modificata, mentre in un'altra si sono ottenuti dati obsoleti o inconsistenti, causando il malfunzionamento dell'algoritmo di business.

Storia

Nel sistema di login, le password erano memorizzate in un oggetto mutabile. A causa di un accesso non sicuro, improvvisamente è "trapelata" la password di un altro utente, poiché lo stesso oggetto veniva utilizzato da più thread.