Comprensione della differenza tra classi mutevoli e immutabili

5

Ho affrontato questa domanda in un'intervista. Ho spiegato che String è immutabile e StringBuffer è una classe mutabile. Non so molto di mutabile e immutabile e non conosco la risposta esatta. Quali sono i concetti chiave per poter distinguere le due idee? C'è un impatto sulle prestazioni quando si sceglie uno rispetto all'altro?

    
posta prakash 11.10.2013 - 17:30
fonte

6 risposte

39

Una classe immutabile è immutabile , come in, non è mutabile. Non puoi cambiarlo Se hai x :: String, puoi essere assolutamente sicuro al 100% che x non cambierà mai e poi mai (o almeno, se lo fa, le persone stanno abusando della flessibilità della tua lingua e hai tutto il diritto di dire loro dove andare ).

Una classe mutevole non è immutabile. Puoi cambiarlo, le altre persone possono cambiarlo e non puoi fare affidamento sul fatto che sia lo stesso. Potrebbe essere cambiato in un'altra discussione, non puoi nemmeno essere sicuro che si trovi nello stesso stato da linea a linea a meno che tu non abbia un buon blocco.

La capacità di alterare lo stato dell'oggetto è il concetto chiave, ma la storia non finisce qui. Potresti voler scegliere una classe immutabile in un ambiente con thread, perché ora non devi preoccuparti del blocco, perché nessuno può scriverlo comunque. Potresti voler scegliere oggetti immutabili in un sistema di grandi dimensioni, perché non puoi essere certo che nessun altro abbia un handle su quel parametro di input e non lo cambierà da sotto la prima possibilità che ottengono. Potresti voler scegliere oggetti immutabili perché riescono a ragionare sul comportamento del tuo codice in piccole unità - come in, se tutto ciò che riguarda una funzione si basa su dati immutabili, puoi guardare quella funzione da sola, garantita.

Ci sono impatti sulle prestazioni, ma non è tutto a senso unico. Gli oggetti immutabili consentono un sacco di ottimizzazioni che non puoi fare su dati mutabili, come la condivisione aggressiva della memoria (perché hey, non può cambiare) o l'inlining più aggressivo. I dati mutabili tendono ad aumentare le prestazioni quando è necessario apportare molte modifiche ai blocchi di memoria.

Se sei interessato a vedere da qualche parte dove l'immutabilità brilla davvero, dai un'occhiata a un linguaggio come Haskell, che è stato progettato da zero per l'immutabilità, consentendo il supporto a livello linguistico per cose come la pigrizia e un sacco di ottimizzazione.

    
risposta data 11.10.2013 - 17:44
fonte
10

Per definire correttamente le classi mutevoli e immutabili, è necessario prima definire cosa significa per un oggetto istanza essere mutabile. Un'istanza dell'oggetto è mutabile se esiste un qualsiasi possibile mezzo (*) tramite il quale lo stato incapsulato potrebbe essere modificato. Un'istanza dell'oggetto è immutabile se il suo stato non può essere modificato. Una classe è immutabile se tutte le istanze di quella classe sono garantite come immutabili, indipendentemente da chi potrebbe contenere riferimenti a esse.

(*) Esistono alcuni approcci come Reflection in cui il codice dannoso potrebbe modificare qualsiasi cosa; la maggior parte delle discussioni sull'immutabilità si concentrano su cose che il codice può "legittimamente" fare e considerano illegittimi tali trucchi di riflessione. Al di fuori delle applicazioni di sicurezza, l'obiettivo normale è far funzionare correttamente gli oggetti per i client ben educati; se una classe si comporta in modo strano quando i client fanno cose illegittime, questo è il problema dei clienti.

Molte discussioni sull'immutabilità ignorano il fatto che mentre tutte le istanze di una classe immutabile sono immutabili, le istanze di una classe mutabile possono anche essere immutabili. Alcune discussioni sulla mutabilità suggeriscono che per una classe "davvero" immutabile, tutti i suoi campi devono essere anche tipi immutabili. Non solo non è vero, ma in molti casi rappresenterebbe un obiettivo quasi impossibile data l'assenza di tipi di array immutabili. Ciò che è necessario è che un oggetto immutabile deve sempre essere certo che nessun riferimento a nessun oggetto mutabile in cui è stato mantenuto lo stato sarà mai esposto a un codice che potrebbe mutarlo. Tutto ciò che il codice esterno potrebbe legittimamente voler fare con l'oggetto incapsulato deve essere fatto attraverso metodi implementati da o per conto dell'oggetto contenente immutabile.

Sarebbe utile se .NET o Java avessero mezzi dichiarativi per specificare che certi oggetti, nonostante siano di tipo mutabile, non dovrebbero mai essere modificati. Sfortunatamente, nessuna di queste funzionalità esiste. Nonostante ciò, una chiave importante per scrivere codice corretto ed efficiente è sapere quali riferimenti identificano cose che sono note come di classi immutabili, quali identificano (quali devono essere) istanze immutabili di classi possibilmente mutevoli, che identificano istanze mutabili non condivise di classi mutevoli e quali non si adattano a nessuno di questi modelli (generalmente perché identificano le "entità"). Molti tipi di bug, alcuni dei quali possono essere molto oscuri, possono derivare dall'uso di uno dei tipi di riferimento sopra indicati come se fosse un altro.

PS - Un framework può raggiungere l'efficienza e la robustezza della convalida const senza i problemi di C ++ - stile "const correctness" se

  • Esistono tipi di archiviazione distinti per "riferimenti all'entità", "riferimento illimitato a valore potenzialmente mutabile", "riferimento di sola lettura a valore potenzialmente mutevole" e "riferimento a valore immutabile"

  • I valori sono clonabili [la clonazione potrebbe essere ampiamente automatizzata se i tipi di riferimenti contenuti sono distinti]

  • I membri possono essere contrassegnati in base al fatto che dovrebbero essere richiamabili su riferimenti di sola lettura o immutabili

  • Ogni istanza di un oggetto include un flag che dice se esistono riferimenti non limitati ad esso

  • Qualsiasi riferimento può essere convertito implicitamente in un riferimento di sola lettura; un riferimento senza restrizioni può anche essere implicitamente convertito in un riferimento immutabile creando un nuovo clone immutabile. Un riferimento di sola lettura può essere convertito implicitamente in immutabile, creando un nuovo clone immutabile, se necessario. Un nuovo oggetto mutevole può essere clonato da qualsiasi riferimento.

Un aspetto essenziale della distinzione "entità" rispetto a "valore" sarebbe che un oggetto è un "valore" solo se (1) è immutabile, o (2) ha un proprietario singolo, e nessun riferimento di alcun tipo esiste all'oggetto che non è sotto il controllo di quel proprietario. Cercare di riguadagnare il controllo su tutti i riferimenti che potrebbero esistere a un oggetto che è stato esposto liberamente al codice esterno sarebbe impossibile, e un meccanismo strettamente applicato al compilatore sarebbe probabilmente troppo restrittivo per essere utile, ma anche se le cose funzionassero come C ++ "cost-correttezza" in cui il codice potrebbe promettersi di comportarsi con una semantica corretta anche quando sembrava "sospetto", ma qualsiasi problema che ne deriverebbe sarebbe colpa del fatto che il programmatore infrangesse la sua promessa, sarebbe un vantaggio significativo rispetto allo status quo. / p>     

risposta data 26.02.2014 - 21:25
fonte
4

Non java, ma ti consiglio di leggere Gli articoli di Eric Lippert sull'immutabilità . Questo problema non è così chiaro come si potrebbe pensare per java. Non c'è alcun impatto intrinseco sulle prestazioni nella scelta dell'uno sull'altro, sebbene possa influire sulle prestazioni a seconda dell'utilizzo esatto.

Il concetto chiave è se e come un oggetto può essere modificato.

    
risposta data 11.10.2013 - 23:20
fonte
3

mutable - liable to change.

immutable - unchanging over time or unable to be changed.

Ok, quindi abbiamo le definizioni. Sappiamo esattamente cosa significano le parole ma come si applicano alla programmazione? Passiamo a due nuove definizioni.

mutable object - an object that is liable to change.

immutable object - an object that is unchanging over time or unable to be changed.

Possiamo usare direttamente la definizione originale quando la mettiamo in termini di programmazione orientata agli oggetti. L'ultima domanda è: come la uso in pratica?

An immutable object must be initialized upon construction and rely only upon other immutable objects once initialized.

    
risposta data 11.10.2013 - 19:27
fonte
3

Vorrei dare un quadro più chiaro sulla comprensione del concetto di classe mutevole e immutabile.
Mutabile significa che il cui valore può essere cambiato al contrario è vero per Immutable come già detto.
In realtà ogni volta che si chiama costruttore di qualsiasi classe stiamo allocando uno spazio di memoria di quel tipo di variabile in heap. per esempio

String str1 = new String("john");
String str2 = str1 ;
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());

Qui come ho chiamato costruttore di string class una memoria è allocata per questa variabile con valore come "john" e il suo codice di riferimento viene restituito a str1 varible. Nella stessa istruzione successiva str2 viene anche fatto puntare alla stessa posizione di memoria. Le due istruzioni println emetteranno lo stesso valore indicando che entrambe le variabili puntano alla stessa posizione di memoria. Ora scrivi questo codice

str2 = "monk";
System.out.println(str2.hashCode());

Nel momento in cui scrivi questa riga, un nuovo spazio di memoria per i dati del tipo di stringa viene creato nell'heap, il suo valore è impostato su "monk" e il riferimento dello stesso viene restituito a str2 e quindi str2 non punta più alla stessa memoria posizione e quindi si otterrà un valore di hash diverso nell'istruzione println. La ragione di ciò è "String is immutable class". Quindi non puoi cambiare il suo valore con qualsiasi mezzo. Per la classe StringBuffer puoi verificarne la mutabilità usando questo codice

StringBuffer sb = new StringBuffer("mohan");    
StringBuffer sb1 = sb.append(" kumar");
System.out.println(sb.hashCode());
System.out.println(sb1.hashCode()+" - "+(sb1==sb)+" - "+sb.hashCode());
    
risposta data 19.01.2015 - 15:08
fonte
0

Utilizzato in termini di primitive (di tipo incorporato) e di oggetti (tipo definito dall'utente). Immutabile significa che non puoi cambiare il valore. Mutabile significa che puoi cambiare il valore.

Molti pensano che le variabili primitive e le variabili oggetto che hanno un modificatore finale davanti a loro siano immutabili, tuttavia, questo non è esattamente vero. La finale quasi non significa immutabile per le variabili. Dai un'occhiata a questo link per un esempio di codice link .

    
risposta data 01.01.2014 - 07:17
fonte

Leggi altre domande sui tag