Perché le stringhe sono immutabili in alcune lingue?


9

String è una classe immutabile in Java. Una classe immutabile è semplicemente una classe le cui istanze non possono essere modificate. Perché il linguaggio di programmazione Java sceglie di rendere immutabili gli oggetti della classe String?


2
@PJTraill Non sembra affatto inevitabile. I letterali stringa in altre lingue non sono immutabili, diciamo, in C, e gli oggetti di altre classi in Java non sono immutabili.
David Richerby,

2
Questa è una domanda sulla progettazione del linguaggio di programmazione. Mi sembra in tema.
David Richerby,

2
@DavidRicherby, i valori letterali di stringa sono immutabili in C (in termini di C90: se il programma tenta di modificare un valore letterale di stringa di una delle due forme, il comportamento è indefinito. Alcune versioni precedenti lo hanno accettato a causa della mancanza di const nella lingua, e lo ha fatto a volte ciò che il programmatore si aspettava, ma non credo che sia mai stato supportato) Penso che tutti abbiano imparato dall'errore all'inizio di FORTRAN che ha permesso di cambiare letterali. Avere letterali che creano un nuovo oggetto mutabile il cui valore iniziale è lo stesso del letterale d'altro canto se non qualcosa di non corretto.
AProgrammer,

1
@AProgrammer Plenty è stato scritto sul perché Java è stato progettato così com'era: sarei sorpreso se non ci fosse nulla di autorevole nelle decisioni di progettazione intorno alla classe String. Ma, anche se i progettisti del linguaggio non hanno mai detto perché String sia immutabile, ciò non rende la domanda fuori tema o addirittura cattiva: significa solo che, sfortunatamente, l'unica risposta corretta è "Non lo sappiamo".
David Richerby,

1
@DavidRicherby Sarebbe meglio se la domanda fosse indipendente dalla lingua. A questo si può rispondere citando una dichiarazione di un sviluppatore Java; vogliamo risposte che spieghino concetti.
Raffaello

Risposte:


9

Questo problema è fortemente connesso al concetto di cosa significhi essere un'istanza di una classe. In termini strettamente orientati agli oggetti, una classe ha un invariante associato: un predicato che vale sempre all'uscita da un metodo (pubblico) della classe. Tale nozione è fondamentale per garantire che l'eredità sia ben definita, ad esempio (fa parte del principio di sostituzione di Liskov ).

Uno dei problemi più perniciosi con Java è che è difficile impedire al codice client di infrangere gli invarianti di classe.

Ad esempio, considera la seguente classe 'ZipCode':

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

Se String non fosse immutabile, sarebbe possibile per un utente di ZipCode chiamare 'get' e cambiare i caratteri in qualsiasi momento successivo, rompendo così l'invariante e distruggendo l'integrità concettuale offerta dall'incapsulamento del concetto ZipCode.

Dal momento che questo tipo di integrità è essenziale per garantire la validità dei sistemi di grandi dimensioni, questa risposta alla tua domanda implora davvero quella più ampia di:

"Perché Java non supporta un analogo della const C ++, o almeno offre versioni immutabili di più delle sue classi di libreria?"


7

Cose come stringhe e date sono naturalmente valori. In termini di C ++, ci aspettiamo che abbiano un costruttore di copie, un operatore di assegnazione e un operatore di uguaglianza, ma non ci aspettiamo mai di prendere il loro indirizzo. Pertanto, non prevediamo che vengano allocati individualmente nell'heap. I metodi virtuali non hanno senso.

Gli oggetti di dominio sono naturalmente riferimenti. Quelli C ++ non hanno costruttore di copie, operatore di assegnazione o operatore di uguaglianza (sono uguali solo se identici). Possiamo prendere il loro indirizzo e ci aspettiamo che vengano assegnati heap. I metodi sono generalmente virtuali.

Java non ha classi di valore, solo quelle di riferimento. I valori sono falsificati con oggetti immutabili. Questo è vero per le stringhe, ma non, sfortunatamente, per le date. La mutabilità delle date di Java ha causato problemi frequenti e ora è deprecata. I valori mutabili non possono essere utilizzati come base per un hash, ad esempio.


Bene, i valori mutabili possono essere usati per l'hash, ma è meglio non modificarli successivamente se si fa affidamento sul codice hash!
gnasher729,

6

Java è stato progettato per consentire l'esecuzione di sottosezioni del codice di un programma in ambienti con limitazioni di sicurezza. Il modo in cui questo requisito è stato implementato è stato impostando un "SecurityManager" su un thread che ha accesso ai parametri di determinate operazioni critiche (ad es. Apertura di un file) e ha chiesto se si potesse consentire o meno all'operazione di procedere. Se le stringhe Java fossero mutabili, un programma potrebbe eludere tali restrizioni creando due thread, uno che eseguiva un'operazione di file aperto che sarebbe consentita, mentre l'altro modificava la stringa in cui memorizzava il nome del file in uno che non era consentito. Esiste quindi la possibilità che il responsabile della sicurezza legga la stringa originale, accetti l'operazione, che verrebbe trasferita al codice di apertura del file che precederebbe l'apertura del secondo file (non consentito).

  • stringhe immutabili
  • eseguire la copia difensiva di qualsiasi stringa critica per la sicurezza prima di verificarne l'accettabilità.

Quest'ultima possibilità farebbe funzionare tutte queste operazioni più lentamente e sarebbe più probabile che l'implementazione contenesse dei bug, quindi l'uso di stringhe immutabili è stata la decisione più sensata.

Più in generale, gli oggetti immutabili sono utili perché consentono la condivisione senza la necessità di effettuare copie difensive (che potrebbe essere necessario anche nel codice non critico per la sicurezza per prevenire bug quando i dati di origine cambiano), quindi anche senza questo requisito la decisione sarebbe comunque ragionevole.


1
Sono contento che qualcuno l'abbia sottolineato, perché James Gosling era completamente chiaro su questa decisione di progettazione. Java è stato progettato in modo da poter eseguire codice non attendibile inviato all'utente su una rete (ad es. In un browser Web o in un set top box digitale). Il motivo principale per cui sono state rese immutabili le stringhe è stato quello di rendere facile per i fornitori o i gestori dei siti (e gli implementatori di librerie standard Java!) Implementare le proprie politiche di sicurezza personalizzate. Le stringhe immutabili chiudono efficacemente un potenziale vettore di attacco in base alla progettazione.
Pseudonimo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.