Perché le stringhe non possono essere modificabili in Java e .NET?


191

Perché hanno deciso di renderli Stringimmutabili in Java e .NET (e in alcune altre lingue)? Perché non l'hanno reso mutevole?


13
Ho avuto lo stesso pensiero, ma ho controllato la posizione dei poster originali e ho scoperto che venivano dal Belgio. Dato che ciò significa che non è probabile che siano di madrelingua inglese. Insieme al fatto che la maggior parte dei nativi conosce bene la lingua, ho deciso di ridurla un po '.
belugabob,

8
Grazie belugabob, ma non sono un lei sono un lui. Apparentemente le persone non considerano le differenze culturali.
chrissie1,

7
Mi scuso - Chrissie è (generalmente) il nome di una ragazza nel Regno Unito - rendendomi vittima di un'altra differenza culturale :-)
belugabob,

Solo una nota, in .NET Stringè effettivamente mutabile internamente. StringBuilderin .NET 2.0 muta una stringa . Lo lascio qui.
Alvin Wong,

In realtà le stringhe .NET sono mutabili. E non è nemmeno un diavolo di un trucco.
Bitterblue,

Risposte:


205

Secondo Effective Java , capitolo 4, pagina 73, 2a edizione:

"Ci sono molte buone ragioni per questo: le classi immutabili sono più facili da progettare, implementare e utilizzare rispetto alle classi mutabili. Sono meno soggette a errori e sono più sicure.

[...]

"Gli oggetti immutabili sono semplici. Un oggetto immutabile può trovarsi esattamente in uno stato, lo stato in cui è stato creato. Se ti assicuri che tutti i costruttori stabiliscano invarianti di classe, allora è garantito che questi invarianti rimarranno veri per sempre, con nessuno sforzo da parte tua.

[...]

Gli oggetti immutabili sono intrinsecamente sicuri per i thread; non richiedono sincronizzazione. Non possono essere danneggiati da più thread che accedono ad essi contemporaneamente. Questo è di gran lunga l'approccio più semplice per raggiungere la sicurezza del filo. In effetti, nessun thread può mai osservare alcun effetto di un altro thread su un oggetto immutabile. Pertanto, gli oggetti immutabili possono essere condivisi liberamente

[...]

Altri piccoli punti dello stesso capitolo:

Non solo puoi condividere oggetti immutabili, ma puoi condividere i loro interni.

[...]

Gli oggetti immutabili sono grandi elementi costitutivi di altri oggetti, sia mutabili che immutabili.

[...]

L'unico vero svantaggio delle classi immutabili è che richiedono un oggetto separato per ciascun valore distinto.


22
Leggi la seconda frase della mia risposta: le classi immutabili sono più facili da progettare, implementare e utilizzare rispetto alle classi mutabili. Sono meno soggetti a errori e sono più sicuri.
PRINCESS FLUFF,

5
@PRINCESSFLUFF Aggiungo che la condivisione di stringhe mutabili è pericolosa anche su un singolo thread. Ad esempio, la copia di un rapporto: report2.Text = report1.Text;. Poi, da qualche altra parte, modificando il testo: report2.Text.Replace(someWord, someOtherWord);. Ciò cambierebbe il primo rapporto e il secondo.
phoog

10
@ Sam non ha chiesto "perché non possono essere mutabili", ha chiesto "perché hanno deciso di renderli immutabili", cosa che risponde perfettamente.
James,

1
@PRINCESSFLUFF Questa risposta non riguarda in modo specifico le stringhe. Questa era la domanda dei PO. È così frustrante - questo succede sempre su SO e anche con domande sull'immutabilità di String. La risposta qui parla dei benefici generali dell'immutabilità. Allora perché non tutti i tipi sono immutabili? Puoi per favore tornare indietro e rivolgermi a String?
Howiecamp,

@Howiecamp Penso che sia implicito dalla risposta che le stringhe avrebbero potuto essere mutabili (nulla impedisce l'esistenza di un'ipotetica classe di stringhe mutabili). Hanno semplicemente deciso di non farlo in questo modo per semplicità e perché copriva il 99% dei casi di utilizzo. Hanno ancora fornito StringBuilder per gli altri casi dell'1%.
Daniel García Rubio,

102

Ci sono almeno due ragioni.

Primo: sicurezza http://www.javafaq.nu/java-article1060.html

Il motivo principale per cui String ha reso immutabile era la sicurezza. Guarda questo esempio: abbiamo un metodo di apertura file con controllo di accesso. Passiamo una stringa a questo metodo per elaborare l'autenticazione necessaria prima che la chiamata venga passata al sistema operativo. Se String era mutabile, in qualche modo era possibile modificarne il contenuto dopo il controllo di autenticazione prima che il sistema operativo ricevesse la richiesta dal programma, quindi è possibile richiedere qualsiasi file. Quindi se hai il diritto di aprire il file di testo nella directory dell'utente ma poi al volo quando in qualche modo riesci a cambiare il nome del file, puoi richiedere di aprire il file "passwd" o qualsiasi altro. Quindi un file può essere modificato e sarà possibile accedere direttamente al sistema operativo.

Secondo: efficienza della memoria http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

JVM mantiene internamente il "String Pool". Per raggiungere l'efficienza della memoria, JVM farà riferimento all'oggetto String dal pool. Non creerà i nuovi oggetti String. Quindi, ogni volta che crei una nuova stringa letterale, JVM verificherà nel pool se esiste già o meno. Se già presente nel pool, è sufficiente fornire il riferimento allo stesso oggetto o creare il nuovo oggetto nel pool. Ci saranno molti riferimenti che rimandano agli stessi oggetti String, se qualcuno cambia il valore, influenzerà tutti i riferimenti. Quindi, il sole ha deciso di renderlo immutabile.


È un buon punto sul riutilizzo, e soprattutto vero se usi String.intern (). Sarebbe stato possibile riutilizzare senza rendere immutabili tutte le stringhe, ma la vita tende a complicarsi a quel punto.
jsight,

3
Nessuno di questi sembra essere terribilmente validi motivi per me in questi tempi.
Brian Knoblauch,

1
Non sono troppo convinto dall'argomento dell'efficienza della memoria (cioè quando due o più oggetti String condividono gli stessi dati e uno viene modificato, quindi entrambi vengono modificati). Gli oggetti CString in MFC riescono a evitarlo usando il conteggio dei riferimenti.
RobH

7
la sicurezza non fa davvero parte della Raison d'être per stringhe immutabili: il tuo sistema operativo copia le stringhe in buffer in modalità kernel e fa un controllo di accesso lì, per evitare attacchi di temporizzazione. Si tratta davvero di sicurezza e prestazioni dei thread :)
snemarch,

1
Anche l'argomento dell'efficienza della memoria non funziona. In un linguaggio nativo come C, le costanti di stringa sono semplicemente dei puntatori ai dati nella sezione dati inizializzata - sono comunque di sola lettura / immutabili. "se qualcuno cambia il valore" - ancora una volta, le stringhe dal pool sono di sola lettura.
wj32,

57

In realtà, i motivi per cui le stringhe sono immutabili in Java non hanno molto a che fare con la sicurezza. I due motivi principali sono i seguenti:

Sicurezza Thead:

Le stringhe sono un tipo di oggetto estremamente diffuso. È quindi più o meno garantito l'utilizzo in un ambiente multi-thread. Le stringhe sono immutabili per assicurarsi che sia sicuro condividere le stringhe tra i thread. La presenza di stringhe immutabili garantisce che quando si passano le stringhe dal thread A a un altro thread B, il thread B non può modificare inaspettatamente la stringa del thread A.

Questo non solo aiuta a semplificare il già complicato compito della programmazione multi-thread, ma aiuta anche con le prestazioni delle applicazioni multi-thread. L'accesso agli oggetti mutabili deve in qualche modo essere sincronizzato quando è possibile accedervi da più thread, per assicurarsi che un thread non tenti di leggere il valore dell'oggetto mentre viene modificato da un altro thread. La corretta sincronizzazione è sia difficile da eseguire correttamente per il programmatore, sia costosa in fase di esecuzione. Gli oggetti immutabili non possono essere modificati e quindi non necessitano di sincronizzazione.

Prestazione:

Sebbene sia stato menzionato l'International String, rappresenta solo un piccolo guadagno in termini di efficienza della memoria per i programmi Java. Solo i letterali stringa sono internati. Ciò significa che solo le stringhe uguali nel codice sorgente condivideranno lo stesso oggetto String. Se il tuo programma crea dinamicamente stringhe uguali, queste saranno rappresentate in oggetti diversi.

Ancora più importante, le stringhe immutabili consentono loro di condividere i propri dati interni. Per molte operazioni sulle stringhe, ciò significa che non è necessario copiare l'array di caratteri sottostante. Ad esempio, supponiamo che tu voglia prendere i primi cinque caratteri di String. In Java, chiameresti myString.substring (0,5). In questo caso, ciò che fa il metodo substring () è semplicemente creare un nuovo oggetto String che condivide il carattere sottostante [] di myString ma che sappia che inizia con l'indice 0 e finisce con l'indice 5 di quel carattere []. Per dirlo in forma grafica, si dovrebbe finire con il seguente:

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

Questo rende questo tipo di operazioni estremamente economico e O (1) poiché l'operazione non dipende né dalla lunghezza della stringa originale, né dalla lunghezza della sottostringa che dobbiamo estrarre. Questo comportamento ha anche alcuni vantaggi di memoria, poiché molte stringhe possono condividere il loro carattere sottostante [].


6
L'implementazione di sottostringhe come riferimenti che condividono il sottostante char[]è una decisione di progettazione piuttosto discutibile. Se leggi un intero file in una singola stringa e mantieni un riferimento a una sottostringa di 1 carattere, l'intero file dovrà essere tenuto in memoria.
Gabe,

5
Esattamente, mi sono imbattuto in quel particolare gotcha mentre creavo un crawler di siti Web che doveva solo estrarre poche parole dall'intera pagina. L'intero codice HTML della pagina era in memoria e, a causa della sottostringa che condivideva il carattere [], ho mantenuto l'intero codice HTML anche se avevo solo bisogno di pochi byte. Una soluzione a ciò consiste nell'utilizzare il nuovo String (original.substring (.., ..)), il costruttore String (String) crea una copia dell'intervallo rilevante dell'array sottostante.
LordOfThePigs il

1
Un addendum per coprire le modifiche successive: da Jave 7, String.substring()esegue una copia completa, al fine di prevenire i problemi menzionati nei commenti sopra. In Java 8, i due campi che consentono la char[]condivisione, ovvero counte offset, vengono rimossi, riducendo così l'impronta di memoria delle istanze di String.
Christian Semrau,

Sono d'accordo con la parte Thead Safety, ma dubito del caso di sottostringa.
Gqqnbig,

@LoveRight: quindi controlla il codice sorgente di java.lang.String ( grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… ), è stato così fino a Java 6 (che era attuale quando è stata scritta questa risposta). Apparentemente sono cambiato in Java 7.
LordOfThePigs il

28

Sicurezza e prestazioni del filo. Se una stringa non può essere modificata, è sicuro e veloce passare un riferimento tra più thread. Se le stringhe fossero mutabili, dovresti sempre copiare tutti i byte della stringa in una nuova istanza o fornire la sincronizzazione. Un'applicazione tipica leggerà una stringa 100 volte per ogni volta che la stringa deve essere modificata. Vedi Wikipedia sull'immutabilità .


11

Si dovrebbe davvero chiedere "perché X dovrebbe essere mutabile?" È meglio passare all'impostazione predefinita per l'immutabilità, a causa dei vantaggi già menzionati da Princess Fluff . Dovrebbe essere un'eccezione che qualcosa sia mutabile.

Sfortunatamente, la maggior parte degli attuali linguaggi di programmazione ha come impostazione predefinita la mutabilità, ma si spera che in futuro l'impostazione predefinita riguardi più l'immutabilità (consultare una Wish List per il prossimo linguaggio di programmazione Mainstream ).


7

Wow! Non riesco a credere alla disinformazione qui. Stringessere immutabili non ha nulla di sicuro. Se qualcuno ha già accesso agli oggetti in un'applicazione in esecuzione (cosa che dovrebbe essere ipotizzata se stai cercando di proteggerti da qualcuno che "hackera" un Stringnella tua app), sarebbero certamente molte altre opportunità disponibili per l'hacking.

È un'idea abbastanza nuova che l'immutabilità di Stringaffrontare i problemi di threading. Hmmm ... Ho un oggetto che viene modificato da due thread diversi. Come lo risolvo? sincronizzare l'accesso all'oggetto? Naawww ... non permettiamo a nessuno di cambiare affatto l'oggetto - questo risolverà tutti i nostri problemi di concorrenza disordinati! In effetti, rendiamo immutabili tutti gli oggetti, e quindi possiamo rimuovere il contratto sincronizzato dal linguaggio Java.

Il vero motivo (sottolineato da altri sopra) è l'ottimizzazione della memoria. È abbastanza comune in qualsiasi applicazione che venga utilizzato ripetutamente lo stesso valore letterale di stringa. È così comune, infatti, che decenni fa molti compilatori hanno ottimizzato la memorizzazione di una sola istanza Stringletterale. Lo svantaggio di questa ottimizzazione è che il codice di runtime che modifica un valore Stringletterale introduce un problema perché sta modificando l'istanza per tutto l'altro codice che lo condivide. Ad esempio, non sarebbe utile che una funzione da qualche parte in un'applicazione cambi il valore Stringletterale "dog"in "cat". A printf("dog")si tradurrebbe in letterali (cioè, li renderebbe immutabili). Alcuni compilatori (con il supporto del sistema operativo) lo farebbero posizionando"cat" scrittura su stdout. Per tale motivo, doveva esserci un modo per proteggersi dal codice che tenta di cambiareStringString letterale in uno speciale segmento di memoria di sola lettura che causerebbe un errore di memoria in caso di tentativo di scrittura.

In Java questo è noto come interning. Il compilatore Java qui sta solo seguendo un'ottimizzazione della memoria standard fatta dai compilatori per decenni. E per affrontare lo stesso problema di questi Stringletterali che vengono modificati in fase di esecuzione, Java rende semplicemente Stringimmutabile la classe (cioè, non ti dà setter che ti permetterebbero di cambiare il Stringcontenuto). Strings non dovrebbe essere immutabile se Stringnon si verificasse l' internamento dei letterali.


3
Non sono assolutamente d'accordo sull'immutabilità e sul commento di threading, mi sembra che tu non riesca proprio a capire il punto. E se Josh Bloch, uno degli implementatori di Java, dice che è stato uno dei problemi di progettazione, come può essere disinformazione?
javashlook,

1
La sincronizzazione è costosa. I riferimenti agli oggetti mutabili devono essere sincronizzati, non così per l'immutabile. Questo è un motivo per rendere immutabili tutti gli oggetti a meno che non debbano essere mutabili. Le stringhe possono essere immutabili, e quindi farlo le rende più efficienti in più thread.
David Thornley,

5
@Jim: l'ottimizzazione della memoria non è la ragione "LA", è la ragione "A". Anche la sicurezza dei thread è una "A", perché gli oggetti immutabili sono intrinsecamente sicuri per i thread e non richiedono costose sincronizzazioni, come ha detto David. La sicurezza del thread è in realtà un effetto collaterale di un oggetto immutabile. Puoi pensare alla sincronizzazione come a un modo per rendere l'oggetto "temporaneamente" immutabile (ReaderWriterLock lo renderà di sola lettura e un blocco regolare lo renderà del tutto inaccessibile, il che ovviamente lo rende anche immutabile).
Triynko,

1
@DavidThornley: la creazione di più percorsi di riferimento indipendenti per un detentore di valori mutabili lo trasforma efficacemente in un'entità e rende molto più difficile ragionare anche a parte problemi di threading. Generalmente, gli oggetti mutabili sono più efficienti di quelli immutabili nel caso in cui esista esattamente un percorso di riferimento per ciascuno, ma gli oggetti immutabili consentono di condividere in modo efficiente il contenuto degli oggetti condividendo i riferimenti. Il modello migliore è esemplificato da Stringe StringBuffer, ma sfortunatamente pochi altri tipi seguono quel modello.
supercat

7

String non è un tipo primitivo, ma normalmente si desidera utilizzarlo con la semantica del valore, ovvero come un valore.

Un valore è qualcosa di cui ti puoi fidare non cambierà alle tue spalle. Se scrivi: String str = someExpr(); non vuoi che cambi a meno che tu non faccia qualcosa con str.

Stringpoiché Objectha una semantica puntatore naturale, per ottenere valore anche la semantica deve essere immutabile.


7

Un fattore è che, se Stringfossero mutabili, gli oggetti che li archiviano Stringdovrebbero stare attenti a conservare le copie, per evitare che i loro dati interni cambino senza preavviso. Dato che gli Strings sono un tipo abbastanza primitivo come i numeri, è bello quando si possono trattarli come se fossero passati per valore, anche se sono passati per riferimento (che aiuta anche a risparmiare memoria).


6

So che questo è un bernoccolo, ma ... Sono davvero immutabili? Considera quanto segue.

public static unsafe void MutableReplaceIndex(string s, char c, int i)
{
    fixed (char* ptr = s)
    {
        *((char*)(ptr + i)) = c;
    }
}

...

string s = "abc";
MutableReplaceIndex(s, '1', 0);
MutableReplaceIndex(s, '2', 1);
MutableReplaceIndex(s, '3', 2);
Console.WriteLine(s); // Prints 1 2 3

Potresti persino renderlo un metodo di estensione.

public static class Extensions
{
    public static unsafe void MutableReplaceIndex(this string s, char c, int i)
    {
        fixed (char* ptr = s)
        {
            *((char*)(ptr + i)) = c;
        }
    }
}

Il che rende il seguente lavoro

s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);

Conclusione: sono in uno stato immutabile noto al compilatore. Di solito quanto sopra si applica solo alle stringhe .NET poiché Java non ha puntatori. Tuttavia, una stringa può essere completamente mutabile utilizzando i puntatori in C #. Non è il modo in cui i puntatori devono essere utilizzati, utilizzati in modo pratico o utilizzati in modo sicuro; è comunque possibile, piegando così l'intera regola "mutabile". Normalmente non è possibile modificare direttamente un indice di una stringa e questo è l'unico modo. Esiste un modo per impedire ciò impedendo le istanze del puntatore di stringhe o eseguendo una copia quando viene indicata una stringa, ma nessuna delle due viene eseguita, il che rende le stringhe in C # non del tutto immutabili.


1
+1. Le stringhe .NET non sono veramente immutabili; infatti, questo viene fatto continuamente nelle classi String e StringBuilder per ragioni perf.
James Ko,

3

Per la maggior parte degli scopi, una "stringa" è (usata / trattata come / pensata / presunta) un'unità atomica significativa , proprio come un numero .

Chiedere perché i singoli caratteri di una stringa non sono modificabili è quindi come chiedersi perché i singoli bit di un numero intero non sono mutabili.

Dovresti sapere perché. Basta pensarci.

Odio dirlo, ma sfortunatamente ne stiamo discutendo perché il nostro linguaggio fa schifo e stiamo provando a usare una sola parola, stringa , per descrivere un concetto complesso o una classe di oggetti contestualmente situati.

Eseguiamo calcoli e confronti con "stringhe" simili a come facciamo con i numeri. Se le stringhe (o numeri interi) fossero mutabili, dovremmo scrivere un codice speciale per bloccare i loro valori in forme locali immutabili al fine di eseguire qualsiasi tipo di calcolo in modo affidabile. Pertanto, è meglio pensare a una stringa come un identificatore numerico, ma invece di essere lunga 16, 32 o 64 bit, potrebbe essere lunga centinaia di bit.

Quando qualcuno dice "stringa", pensiamo tutti a cose diverse. Coloro che la considerano semplicemente come un insieme di personaggi, senza uno scopo particolare in mente, saranno ovviamente sconvolti dal fatto che qualcuno abbia appena deciso che non dovrebbero essere in grado di manipolare quei personaggi. Ma la classe "stringa" non è solo una matrice di caratteri. È un STRING, non un char[]. Ci sono alcune ipotesi di base sul concetto che chiamiamo "stringa", e generalmente possono essere descritte come unità atomiche significative di dati codificati come un numero. Quando le persone parlano di "manipolazione di stringhe", forse stanno davvero parlando di manipolazione di personaggi per costruire stringhe , e StringBuilder è ottimo per questo.

Considera per un momento come sarebbe se le stringhe fossero mutabili. La seguente funzione API potrebbe essere indotto a ritornare le informazioni per un altro utente se il mutevole stringa username è intenzionalmente o modificato da un altro filo quando questa funzione lo utilizza:

string GetPersonalInfo( string username, string password )
{
    string stored_password = DBQuery.GetPasswordFor( username );
    if (password == stored_password)
    {
        //another thread modifies the mutable 'username' string
        return DBQuery.GetPersonalInfoFor( username );
    }
}

La sicurezza non riguarda solo il "controllo degli accessi", ma anche "sicurezza" e "garanzia di correttezza". Se un metodo non può essere facilmente scritto e dipende da eseguire un semplice calcolo o confronto in modo affidabile, allora non è sicuro chiamarlo, ma sarebbe sicuro rimettere in discussione il linguaggio di programmazione stesso.


In C #, una stringa è mutabile dal suo puntatore (usa unsafe) o semplicemente attraverso la riflessione (puoi ottenere facilmente il campo sottostante). Questo annulla il punto sulla sicurezza, come chiunque voglia intenzionalmente cambiare una stringa, può farlo abbastanza facilmente. Tuttavia, fornisce sicurezza ai programmatori: a meno che tu non faccia qualcosa di speciale, la stringa è garantita immutabile (ma non è thread-safe!).
Abel

Sì, è possibile modificare i byte di qualsiasi oggetto dati (stringa, int, ecc.) Tramite i puntatori. Tuttavia, stiamo parlando del motivo per cui la classe stringa è immutabile, nel senso che non ha metodi pubblici incorporati per modificarne i caratteri. Stavo dicendo che una stringa è molto simile a un numero in quanto manipolare singoli caratteri non ha più senso che manipolare singoli bit di un numero (quando trattate una stringa come un intero token (non come un array di byte) e un numero come un valore numerico (non come un campo di bit). Stiamo parlando a livello di oggetto concettuale, non a livello di oggetto secondario.
Triynko,

2
E solo per chiarire, i puntatori nel codice orientato agli oggetti sono intrinsecamente non sicuri, proprio perché aggirano le interfacce pubbliche definite per una classe. Quello che stavo dicendo era che una funzione poteva essere facilmente ingannata se l'interfaccia pubblica per una stringa permettesse di essere modificata da altri thread. Naturalmente, può sempre essere ingannato accedendo ai dati direttamente con i puntatori, ma non così facilmente o involontariamente.
Triynko,

1
I "puntatori nel codice orientato agli oggetti sono intrinsecamente non sicuri" a meno che non vengano chiamati riferimenti . I riferimenti in Java non sono diversi dai puntatori in C ++ (solo l'aritmetica dei puntatori è disabilitata). Un concetto diverso è la gestione della memoria che può essere gestita o manuale, ma è una cosa diversa. Potresti avere una semantica di riferimento (puntatori senza aritmetica) senza avere GC (il contrario sarebbe più difficile nel senso che la semantica della raggiungibilità sarebbe più difficile da rendere pulita, ma non irrealizzabile)
David Rodríguez - dribeas

L'altra cosa è che se le stringhe sono quasi immutabili, ma non del tutto (non conosco abbastanza CLI qui), ciò può essere davvero negativo per motivi di sicurezza. In alcune precedenti implementazioni Java potresti farlo, e ho trovato un frammento di codice che lo utilizzava per interiorizzare le stringhe (prova a localizzare un'altra stringa interna che ha lo stesso valore, condividi il puntatore, rimuovi il vecchio blocco di memoria) e usa la backdoor riscrivere il contenuto della stringa forzando un comportamento errato in una classe diversa. (Considera di riscrivere "SELEZIONA *" in "ELIMINA")
David Rodríguez - dribeas,

3

L'immutabilità non è così strettamente legata alla sicurezza. Per questo, almeno in .NET, ottieni la SecureStringclasse.

Modifica successiva: in Java troverai GuardedStringun'implementazione simile.


2

La decisione di rendere mutevole la stringa in C ++ causa molti problemi, vedi questo eccellente articolo di Kelvin Henney sulla Mad COW Disease .

COW = Copia in scrittura.


2

È un compromesso. Stringvanno nel Stringpool e quando crei più messaggi identici Stringcondividono la stessa memoria. I progettisti hanno pensato che questa tecnica di salvataggio della memoria avrebbe funzionato bene per il caso comune, poiché i programmi tendono a macinare molto sulle stesse stringhe.

Il rovescio della medaglia è che le concatenazioni fanno molti extra Stringche sono solo di transizione e diventano solo spazzatura, danneggiando effettivamente le prestazioni della memoria. Hai StringBuffere StringBuilder(in Java, StringBuilderè anche in .NET) da utilizzare per conservare la memoria in questi casi.


1
Tieni presente che il "pool di stringhe" non viene utilizzato automaticamente per TUTTE le stringhe, a meno che tu non usi esplicitamente le stringhe "inter ()".
jsight,

2

Strings in Java non sono veramente immutabili, puoi cambiare il loro valore usando il reflection eo caricando le classi. Non dovresti dipendere da quella proprietà per sicurezza. Per esempi vedi: Trucco magico in Java


1
Credo che sarai in grado di fare questi trucchi solo se il tuo codice è in esecuzione con piena fiducia, quindi non c'è perdita di sicurezza. È inoltre possibile utilizzare JNI per scrivere direttamente nella posizione di memoria in cui sono archiviate le stringhe.
Antoine Aubry,

In realtà credo che tu possa cambiare qualsiasi oggetto immutabile mediante la riflessione.
Gqqnbig,

0

L'immutabilità è buona. Vedi Java efficace. Se dovessi copiare una stringa ogni volta che la passavi, sarebbe un sacco di codice soggetto a errori. Hai anche confusione su quali modifiche influenzano quali riferimenti. Allo stesso modo in cui Integer deve essere immutabile per comportarsi come int, le stringhe devono comportarsi come immutabili per agire come primitivi. In C ++ il passaggio di stringhe per valore fa ciò senza menzione esplicita nel codice sorgente.


0

C'è un'eccezione per quasi tutte le regole:

using System;
using System.Runtime.InteropServices;

namespace Guess
{
    class Program
    {
        static void Main(string[] args)
        {
            const string str = "ABC";

            Console.WriteLine(str);
            Console.WriteLine(str.GetHashCode());

            var handle = GCHandle.Alloc(str, GCHandleType.Pinned);

            try
            {
                Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');

                Console.WriteLine(str);
                Console.WriteLine(str.GetHashCode());
            }
            finally
            {
                handle.Free();
            }
        }
    }
}

-1

È in gran parte per motivi di sicurezza. È molto più difficile proteggere un sistema se non ci si può fidare che i propri dispositivi Stringsiano a prova di manomissione.


1
Puoi fare un esempio di cosa intendi per "antimanomissione". Questa risposta sembra davvero fuori contesto.
Gergely Orosz,
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.