Eu tinha o mesmo pensamento, mas verifiquei a localização dos pôsteres originais e descobri que eles são da Bélgica. Dado que isso significa que eles provavelmente não são falantes nativos de inglês. Juntamente com o fato de que a maioria dos nativos tem um entendimento fraco da língua, decidi dar uma folga nela.
21009 belugabob
8
Obrigado belugabob, mas eu não sou ela, sou ele. Aparentemente, as pessoas não consideram as diferenças culturais.
Chrissie1
7
Minhas desculpas - chrissie é (geralmente) um nome de menina no Reino Unido - fazendo-me vítima de uma outra diferença cultural :-)
Na verdade, as seqüências .NET são mutáveis. E não é nem um pedaço de um hack.
Bitterblue
Respostas:
204
De acordo com o Effective Java , capítulo 4, página 73, 2ª edição:
"Há muitas boas razões para isso: classes imutáveis são mais fáceis de projetar, implementar e usar do que classes mutáveis. Elas são menos propensas a erros e são mais seguras.
[...]
" Objetos imutáveis são simples. Um objeto imutável pode estar em exatamente um estado, o estado em que foi criado. Se você garantir que todos os construtores estabeleçam invariantes de classe, é garantido que esses invariantes permanecerão verdadeiros o tempo todo, com nenhum esforço de sua parte.
[...]
Objetos imutáveis são inerentemente seguros para threads; eles não requerem sincronização. Eles não podem ser corrompidos por vários threads acessando-os simultaneamente. Essa é, de longe, a abordagem mais fácil para garantir a segurança do thread. De fato, nenhum encadeamento pode observar qualquer efeito de outro encadeamento em um objeto imutável. Portanto,
objetos imutáveis podem ser compartilhados livremente
[...]
Outros pequenos pontos do mesmo capítulo:
Não apenas você pode compartilhar objetos imutáveis, mas também os internos.
[...]
Objetos imutáveis são ótimos elementos de construção para outros objetos, sejam mutáveis ou imutáveis.
[...]
A única desvantagem real das classes imutáveis é que elas exigem um objeto separado para cada valor distinto.
Leia a segunda frase da minha resposta: Classes imutáveis são mais fáceis de projetar, implementar e usar do que classes mutáveis. Eles são menos propensos a erros e são mais seguros.
PRINCESS FLUFF
5
@PRINCESSFLUFF Gostaria de acrescentar que o compartilhamento de seqüências mutáveis é perigoso, mesmo em um único thread. Por exemplo, a cópia de um relatório: report2.Text = report1.Text;. Em seguida, em outro lugar, modificar o texto: report2.Text.Replace(someWord, someOtherWord);. Isso mudaria o primeiro relatório e o segundo.
Phoog
10
@ Sam, ele não perguntou "por que eles não podem ser mutáveis", ele perguntou "por que eles decidiram tornar imutáveis", o que responde perfeitamente.
James
1
@PRINCESSFLUFF Esta resposta não trata das strings especificamente. Essa foi a pergunta dos OPs. É tão frustrante - isso acontece o tempo todo no SO e também nas questões de imutabilidade de String. A resposta aqui fala sobre os benefícios gerais da imutabilidade. Então, por que todos os tipos não são imutáveis? Você pode voltar e abordar String?
Howiecamp
@ Howiecamp Eu acho que está implícito pela resposta que as strings poderiam ter sido mutáveis (nada impede que exista uma classe de mutável hipotética). Eles apenas decidiram não fazê-lo dessa maneira por simplicidade e porque abrangia os 99% casos de uso. Eles ainda forneceram o StringBuilder para os outros casos de 1%.
A principal razão pela qual String tornou imutável foi a segurança. Veja este exemplo: Temos um método de arquivo aberto com verificação de login. Passamos uma String para esse método para processar a autenticação necessária antes que a chamada seja passada para o SO. Se String era mutável, era possível, de alguma forma, modificar seu conteúdo após a verificação de autenticação antes que o SO recebesse solicitação do programa, é possível solicitar qualquer arquivo. Portanto, se você tem o direito de abrir um arquivo de texto no diretório do usuário, mas rapidamente quando, de alguma forma, você consegue alterar o nome do arquivo, pode solicitar a abertura do arquivo "passwd" ou qualquer outro. Em seguida, um arquivo pode ser modificado e será possível fazer login diretamente no sistema operacional.
A JVM mantém internamente o "Conjunto de String". Para obter a eficiência da memória, a JVM consultará o objeto String do pool. Não criará os novos objetos String. Portanto, sempre que você cria uma nova literal de cadeia, a JVM verifica no conjunto se ela já existe ou não. Se já estiver presente no pool, basta fornecer a referência ao mesmo objeto ou criar o novo objeto no pool. Haverá muitas referências que apontam para os mesmos objetos String, se alguém alterar o valor, isso afetará todas as referências. Então, o sol decidiu torná-lo imutável.
É um bom argumento sobre a reutilização, e especialmente verdadeiro se você usar String.intern (). Teria sido possível reutilizar sem tornar todas as cordas imutáveis, mas a vida tende a ficar complicada nesse ponto.
jsight
3
Nenhum deles parece ser uma razão terrivelmente válida para mim hoje em dia.
Brian Knoblauch
1
Não estou muito convencido com o argumento de eficiência de memória (ou seja, quando dois ou mais objetos String compartilham os mesmos dados e um é modificado, então ambos são modificados). Objetos CString no MFC contornam isso usando a contagem de referência.
2133 RobH
7
a segurança não é realmente parte do Raison d'être para seqüências imutáveis - seu sistema operacional copia as seqüências para buffers no modo kernel e faz a verificação de acesso lá, para evitar ataques de tempo. É realmente tudo sobre a segurança e desempenho :) fio
snemarch
1
O argumento de eficiência de memória também não funciona. Em uma linguagem nativa como C, constantes de string são simplesmente ponteiros para dados na seção de dados inicializados - eles são somente leitura / imutáveis de qualquer maneira. "se alguém alterar o valor" - novamente, as strings do pool são somente leitura de qualquer maneira.
wj32 24/03/09
57
Na verdade, as razões pelas quais a string é imutável no java não têm muito a ver com segurança. Os dois principais motivos são os seguintes:
Segurança do cabeçote:
Strings são um tipo de objeto extremamente amplamente utilizado. Portanto, é mais ou menos garantido o uso em um ambiente multithread. As strings são imutáveis para garantir que seja seguro compartilhar as strings entre os threads. Ter uma sequência imutável garante que, ao passar sequências do segmento A para outro segmento B, o segmento B não possa modificar inesperadamente a sequência do segmento A.
Isso não apenas ajuda a simplificar a tarefa já bastante complicada da programação multithread, como também ajuda no desempenho de aplicativos multithread. O acesso a objetos mutáveis deve, de alguma forma, ser sincronizado quando eles podem ser acessados de vários threads, para garantir que um thread não tente ler o valor do seu objeto enquanto estiver sendo modificado por outro thread. A sincronização adequada é difícil de fazer corretamente para o programador e é cara no tempo de execução. Objetos imutáveis não podem ser modificados e, portanto, não precisam de sincronização.
Atuação:
Embora a internação por String tenha sido mencionada, ela representa apenas um pequeno ganho em eficiência de memória para programas Java. Somente literais de string são internados. Isso significa que apenas as strings que são iguais no seu código-fonte compartilharão o mesmo objeto String. Se o seu programa criar dinamicamente seqüências iguais, elas serão representadas em objetos diferentes.
Mais importante, cadeias imutáveis permitem que eles compartilhem seus dados internos. Para muitas operações de cadeia, isso significa que a matriz subjacente de caracteres não precisa ser copiada. Por exemplo, suponha que você queira pegar os cinco primeiros caracteres de String. Em Java, você chamaria myString.substring (0,5). Nesse caso, o que o método substring () faz é simplesmente criar um novo objeto String que compartilhe o char subjacente [] do myString, mas quem sabe que ele começa no índice 0 e termina no índice 5 desse caractere []. Para colocar isso em forma gráfica, você terminaria com o seguinte:
| myString |
v v
"The quick brown fox jumps over the lazy dog"<-- shared char[]^^|| myString.substring(0,5)
Isso torna esse tipo de operação extremamente barato e O (1), pois a operação não depende do comprimento da string original nem do comprimento da substring que precisamos extrair. Esse comportamento também possui alguns benefícios de memória, pois muitas seqüências de caracteres podem compartilhar seus caracteres subjacentes [].
Implementar substrings como referências que compartilham o subjacente char[]é uma decisão de design bastante questionável. Se você ler um arquivo inteiro em uma única sequência e manter uma referência a apenas uma substring de 1 caractere, o arquivo inteiro deverá ser mantido na memória.
Gabe
5
Exatamente, eu encontrei essa pegadinha em particular ao criar um rastreador de site que só precisava extrair algumas palavras da página inteira. O código HTML da página inteira estava na memória e, devido à subseqüência do compartilhamento do char [], eu mantive o código HTML inteiro, apesar de precisar apenas de alguns bytes. Uma solução alternativa para isso é usar o novo String (original.substring (.., ..)), o construtor String (String) faz uma cópia do intervalo relevante da matriz subjacente.
LordOfThePigs
1
Um adendo para cobrir alterações subseqüentes: Desde o Jave 7, String.substring()realiza uma cópia completa, a fim de evitar os problemas mencionados nos comentários acima. No Java 8, os dois campos que permitem o char[]compartilhamento, ou seja , counte offset, são removidos, reduzindo assim o consumo de memória das instâncias String.
Christian Semrau 24/03
Concordo com a parte Thead Safety, mas duvido do caso de substring.
Segurança e desempenho da linha. Se uma string não puder ser modificada, é seguro e rápido passar uma referência entre vários threads. Se as strings fossem mutáveis, você sempre teria que copiar todos os bytes da string para uma nova instância ou fornecer sincronização. Um aplicativo típico lê uma string 100 vezes para cada vez que ela precisar ser modificada. Veja a Wikipedia sobre imutabilidade .
Deve-se realmente perguntar: "por que X deveria ser mutável?" É melhor deixar a imutabilidade por causa dos benefícios já mencionados pela princesa Fluff . Deve ser uma exceção que algo seja mutável.
Uau! Não acredito na desinformação aqui. Stringser imutável não tem nada com segurança. Se alguém já tiver acesso aos objetos em um aplicativo em execução (o que teria que ser assumido se você estivesse tentando se proteger contra alguém 'hackeando' um Stringno seu aplicativo), certamente haveria muitas outras oportunidades disponíveis para hackers.
É uma idéia bastante nova que a imutabilidade Stringestá abordando problemas de segmentação. Hmmm ... Eu tenho um objeto que está sendo alterado por dois threads diferentes. Como eu resolvo isso? sincronizar o acesso ao objeto? Naawww ... não vamos deixar ninguém mudar o objeto - isso corrigirá todos os nossos problemas de concorrência desordenados! De fato, vamos tornar todos os objetos imutáveis e, em seguida, podemos remover o controle sincronizado da linguagem Java.
O verdadeiro motivo (apontado por outros acima) é a otimização de memória. É bastante comum em qualquer aplicativo que a mesma string literal seja usada repetidamente. É tão comum, de fato, que décadas atrás, muitos compiladores fizeram a otimização de armazenar apenas uma única instância de um Stringliteral. A desvantagem dessa otimização é que o código de tempo de execução que modifica um Stringliteral introduz um problema porque está modificando a instância para todos os outros códigos que o compartilham. Por exemplo, não seria bom para uma função em algum lugar de um aplicativo alterar o Stringliteral "dog"para "cat". A printf("dog")resultaria na "cat"gravação em stdout. Por esse motivo, precisava haver uma maneira de se proteger contra códigos que tentam mudarStringliterais (ou seja, torná-los imutáveis). Alguns compiladores (com suporte do sistema operacional) conseguiriam isso colocando Stringliteralmente em um segmento de memória somente leitura especial que causaria uma falha na memória se fosse feita uma tentativa de gravação.
Em Java, isso é conhecido como interning. O compilador Java aqui está apenas seguindo uma otimização de memória padrão feita por compiladores há décadas. E para resolver o mesmo problema desses Stringliterais sendo modificados em tempo de execução, o Java simplesmente torna a Stringclasse imutável (ou seja, não fornece setters que permitam alterar o Stringconteúdo). Strings não precisaria ser imutável se a internação de Stringliterais não ocorresse.
Eu discordo totalmente sobre imutabilidade e comentário de enfiar, parece-me que você não está entendendo bem o ponto. E se Josh Bloch, um dos implementadores de Java, diz que esse foi um dos problemas de design, como isso pode ser desinformação?
Javashlook 27/03/09
1
A sincronização é cara. As referências a objetos mutáveis precisam ser sincronizadas, não para imutáveis. Essa é uma razão para tornar todos os objetos imutáveis, a menos que tenham que ser mutáveis. As strings podem ser imutáveis e, portanto, isso as torna mais eficientes em vários threads.
David Thornley
5
@ Jim: A otimização de memória não é a razão 'THE', é a razão 'A'. A segurança de threads também é um motivo 'A', porque objetos imutáveis são inerentemente seguros para threads e não requerem sincronização cara, como David mencionou. A segurança da linha é na verdade um efeito colateral de um objeto imutável. Você pode pensar na sincronização como uma maneira de tornar o objeto "temporariamente" imutável (o ReaderWriterLock o tornará somente leitura, e um bloqueio regular o tornará inacessível por completo, o que obviamente também o torna imutável).
Triynko
1
@DavidThornley: A criação de vários caminhos de referência independentes para um detentor de valor mutável efetivamente o transforma em uma entidade e torna muito mais difícil argumentar, além de problemas de segmentação. Geralmente, objetos mutáveis são mais eficientes que objetos imutáveis nos casos em que exista exatamente um caminho de referência para cada um, mas objetos imutáveis permitem que o conteúdo dos objetos seja compartilhado com eficiência, compartilhando referências. O melhor padrão é exemplificado por Stringe StringBuffer, mas infelizmente poucos outros tipos seguem esse modelo.
supercat 08/02
7
String não é um tipo primitivo, mas você normalmente deseja usá-lo com semântica de valores, ou seja, como um valor.
Um valor é algo em que você pode confiar não mudará pelas suas costas. Se você escrever: String str = someExpr();
Você não quer que isso mude, a menos que você faça algo str.
Stringcomo uma Objectsemântica de ponteiro naturalmente, para obter semântica de valor, ela precisa ser imutável.
Um fator é que, se Strings forem mutáveis, os objetos que armazenam Strings terão que ter cuidado para armazenar cópias, para que seus dados internos não sejam alterados sem aviso prévio. Dado que Strings são um tipo bastante primitivo, como números, é bom quando se pode tratá-los como se fossem passados por valor, mesmo se passados por referência (o que também ajuda a economizar memória).
Conclusão: Eles estão em um estado imutável, conhecido pelo compilador. É claro que o exposto acima se aplica apenas a seqüências .NET, pois o Java não possui ponteiros. No entanto, uma string pode ser totalmente mutável usando ponteiros em C #. Não é assim que os ponteiros devem ser usados, têm uso prático ou são usados com segurança; no entanto, é possível, dobrando assim toda a regra "mutável". Normalmente, você não pode modificar um índice diretamente de uma string e esse é o único caminho. Existe uma maneira de evitar isso, impedindo a ocorrência de instâncias de ponteiro ou fazendo uma cópia quando uma string é apontada, mas nenhuma delas é feita, o que torna as strings em C # não totalmente imutáveis.
+1. Strings .NET não são realmente imutáveis; de fato, isso é feito o tempo todo nas classes String e StringBuilder por razões de desempenho.
James Ko
3
Para a maioria dos propósitos, uma "string" é (usada / tratada como / considerada uma suposta) uma unidade atômica significativa , assim como um número .
Perguntar por que os caracteres individuais de uma string não são mutáveis é, portanto, como perguntar por que os bits individuais de um número inteiro não são mutáveis.
Você deveria saber o porquê. Apenas pense sobre isso.
Detesto dizer isso, mas infelizmente estamos debatendo isso porque nossa linguagem é péssima e estamos tentando usar uma única palavra, string , para descrever um conceito ou classe de objeto complexo e contextualmente situado.
Realizamos cálculos e comparações com "strings" semelhantes à forma como fazemos com números. Se strings (ou números inteiros) fossem mutáveis, teríamos que escrever um código especial para bloquear seus valores em formas locais imutáveis, a fim de realizar qualquer tipo de cálculo de maneira confiável. Portanto, é melhor pensar em uma sequência como um identificador numérico, mas, em vez de ter 16, 32 ou 64 bits, pode ter centenas de bits.
Quando alguém diz "string", todos pensamos em coisas diferentes. Aqueles que pensam nisso simplesmente como um conjunto de caracteres, sem nenhum objetivo específico em mente, ficarão horrorizados com o fato de alguém ter decidido que não deveria ser capaz de manipular esses caracteres. Mas a classe "string" não é apenas uma matriz de caracteres. É um STRING, não um char[]. Existem algumas suposições básicas sobre o conceito que chamamos de "string", e geralmente pode ser descrito como uma unidade atômica significativa de dados codificados, como um número. Quando as pessoas falam sobre "manipular strings", talvez estejam realmente falando sobre como manipular caracteres para criar strings , e um StringBuilder é ótimo para isso.
Considere por um momento como seria se as cordas fossem mutáveis. A função de API a seguir pode ser induzida a retornar informações para um usuário diferente se a sequência de nome de usuário mutável for intencional ou não intencionalmente modificada por outro encadeamento enquanto esta função a estiver usando:
Segurança não é apenas sobre 'controle de acesso', é também sobre 'segurança' e 'garantia de correção'. Se um método não puder ser facilmente escrito e dependido para executar um cálculo simples ou uma comparação confiável, não é seguro chamá-lo, mas seria seguro questionar a própria linguagem de programação.
No C #, uma string é mutável pelo ponteiro (uso unsafe) ou simplesmente através da reflexão (você pode obter o campo subjacente facilmente). Isso anula a questão da segurança, pois qualquer pessoa que queira alterar intencionalmente uma string pode fazê-lo facilmente. No entanto, fornece segurança aos programadores: a menos que você faça algo especial, a string é garantida imutável (mas não é segura para threads!).
Abel
Sim, você pode alterar os bytes de qualquer objeto de dados (string, int, etc.) por meio de ponteiros. No entanto, estamos falando sobre por que a classe string é imutável no sentido de que não possui métodos públicos incorporados para modificar seus caracteres. Eu estava dizendo que uma string é muito parecida com um número em que manipular caracteres individuais não faz mais sentido do que manipular bits individuais de um número (quando você trata uma string como um token inteiro (não como uma matriz de bytes) e um número como um valor numérico (não como um campo de bits) Estamos falando no nível do objeto conceitual, não no nível de sub-objeto..
Triynko
2
E apenas para esclarecer, os ponteiros no código orientado a objetos são inerentemente inseguros, exatamente porque contornam as interfaces públicas definidas para uma classe. O que eu estava dizendo era que uma função poderia ser facilmente enganada se a interface pública de uma string permitir que ela seja modificada por outros threads. Obviamente, sempre pode ser enganado acessando dados diretamente com ponteiros, mas não com tanta facilidade ou sem intenção.
Triynko
1
'ponteiros no código orientado a objetos são inerentemente inseguros', a menos que você os chame de referências . As referências em Java não são diferentes dos ponteiros em C ++ (apenas a aritmética dos ponteiros está desativada). Um conceito diferente é o gerenciamento de memória que pode ser gerenciado ou manual, mas isso é uma coisa diferente. Você poderia ter semântica de referência (ponteiros sem aritmética) sem ter GC (o contrário seria mais difícil no sentido de que a semântica de acessibilidade seria mais difícil de fazer a limpeza, mas não inviável)
David Rodríguez - dribeas
A outra coisa é que, se as strings são quase imutáveis, mas não totalmente (não sei CLI suficiente aqui), isso pode ser muito ruim por motivos de segurança. Em algumas implementações Java mais antigas, era possível fazer isso, e eu encontrei um trecho de código usado para internalizar cadeias (tente localizar outra cadeia interna que tenha o mesmo valor, compartilhe o ponteiro, remova o bloco de memória antigo) e usei o backdoor reescrever o conteúdo da string forçando um comportamento incorreto em uma classe diferente. (Considere reescrever "SELECT *" para "DELETE")
David Rodríguez - dribeas 27/05
3
A imutabilidade não está tão intimamente ligada à segurança. Por isso, pelo menos no .NET, você obtém a SecureStringclasse.
Edição posterior: em Java, você encontrará GuardedStringuma implementação semelhante.
É uma troca. Strings entram no Stringpool e quando você cria vários Strings idênticos, eles compartilham a mesma memória. Os designers imaginaram que essa técnica de economia de memória funcionaria bem para o caso comum, já que os programas tendem a se desgastar muito pelas mesmas seqüências.
A desvantagem é que as concatenações produzem muitos Strings extras que são apenas transitórios e se tornam lixo, prejudicando o desempenho da memória. Você tem StringBuffere StringBuilder(em Java, StringBuildertambém está no .NET) para usar para preservar a memória nesses casos.
Lembre-se de que o "pool de strings" não é usado automaticamente para TODAS as strings, a menos que você use explicitamente as strings "inter ()".
jsight
2
Strings em Java não são realmente imutáveis, você pode alterar seus valores usando reflexão e / ou carregamento de classe. Você não deve depender dessa propriedade por segurança. Para exemplos, consulte: Truque de mágica em Java
Acredito que você só poderá fazer esses truques se seu código estiver sendo executado com total confiança, portanto, não haverá perda de segurança. Você também pode usar o JNI para escrever diretamente no local da memória em que as strings estão armazenadas.
Antoine Aubry
Na verdade, acredito que você pode mudar qualquer objeto imutável pela reflexão.
Gqqnbig
0
Imutabilidade é boa. Consulte Java efetivo. Se você tivesse que copiar uma String toda vez que a passasse, isso seria muito código propenso a erros. Você também tem confusão sobre quais modificações afetam quais referências. Da mesma maneira que o Inteiro precisa ser imutável para se comportar como int, as Strings precisam se comportar como imutáveis para agir como primitivas. No C ++, a passagem de cadeias por valor faz isso sem menção explícita no código-fonte.
using System;
using System.Runtime.InteropServices;
namespace Guess{classProgram{staticvoidMain(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();}}}}
É principalmente por razões de segurança. É muito mais difícil proteger um sistema se você não pode confiar que seus sistemas Stringsão à prova de violações.
String
é realmente mutável internamente.StringBuilder
no .NET 2.0 modifica uma string . Vou deixar aqui.Respostas:
De acordo com o Effective Java , capítulo 4, página 73, 2ª edição:
Outros pequenos pontos do mesmo capítulo:
fonte
report2.Text = report1.Text;
. Em seguida, em outro lugar, modificar o texto:report2.Text.Replace(someWord, someOtherWord);
. Isso mudaria o primeiro relatório e o segundo.Há pelo menos duas razões.
Primeiro - segurança http://www.javafaq.nu/java-article1060.html
Segundo - eficiência de memória http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html
fonte
Na verdade, as razões pelas quais a string é imutável no java não têm muito a ver com segurança. Os dois principais motivos são os seguintes:
Segurança do cabeçote:
Strings são um tipo de objeto extremamente amplamente utilizado. Portanto, é mais ou menos garantido o uso em um ambiente multithread. As strings são imutáveis para garantir que seja seguro compartilhar as strings entre os threads. Ter uma sequência imutável garante que, ao passar sequências do segmento A para outro segmento B, o segmento B não possa modificar inesperadamente a sequência do segmento A.
Isso não apenas ajuda a simplificar a tarefa já bastante complicada da programação multithread, como também ajuda no desempenho de aplicativos multithread. O acesso a objetos mutáveis deve, de alguma forma, ser sincronizado quando eles podem ser acessados de vários threads, para garantir que um thread não tente ler o valor do seu objeto enquanto estiver sendo modificado por outro thread. A sincronização adequada é difícil de fazer corretamente para o programador e é cara no tempo de execução. Objetos imutáveis não podem ser modificados e, portanto, não precisam de sincronização.
Atuação:
Embora a internação por String tenha sido mencionada, ela representa apenas um pequeno ganho em eficiência de memória para programas Java. Somente literais de string são internados. Isso significa que apenas as strings que são iguais no seu código-fonte compartilharão o mesmo objeto String. Se o seu programa criar dinamicamente seqüências iguais, elas serão representadas em objetos diferentes.
Mais importante, cadeias imutáveis permitem que eles compartilhem seus dados internos. Para muitas operações de cadeia, isso significa que a matriz subjacente de caracteres não precisa ser copiada. Por exemplo, suponha que você queira pegar os cinco primeiros caracteres de String. Em Java, você chamaria myString.substring (0,5). Nesse caso, o que o método substring () faz é simplesmente criar um novo objeto String que compartilhe o char subjacente [] do myString, mas quem sabe que ele começa no índice 0 e termina no índice 5 desse caractere []. Para colocar isso em forma gráfica, você terminaria com o seguinte:
Isso torna esse tipo de operação extremamente barato e O (1), pois a operação não depende do comprimento da string original nem do comprimento da substring que precisamos extrair. Esse comportamento também possui alguns benefícios de memória, pois muitas seqüências de caracteres podem compartilhar seus caracteres subjacentes [].
fonte
char[]
é uma decisão de design bastante questionável. Se você ler um arquivo inteiro em uma única sequência e manter uma referência a apenas uma substring de 1 caractere, o arquivo inteiro deverá ser mantido na memória.String.substring()
realiza uma cópia completa, a fim de evitar os problemas mencionados nos comentários acima. No Java 8, os dois campos que permitem ochar[]
compartilhamento, ou seja ,count
eoffset
, são removidos, reduzindo assim o consumo de memória das instâncias String.Segurança e desempenho da linha. Se uma string não puder ser modificada, é seguro e rápido passar uma referência entre vários threads. Se as strings fossem mutáveis, você sempre teria que copiar todos os bytes da string para uma nova instância ou fornecer sincronização. Um aplicativo típico lê uma string 100 vezes para cada vez que ela precisar ser modificada. Veja a Wikipedia sobre imutabilidade .
fonte
Deve-se realmente perguntar: "por que X deveria ser mutável?" É melhor deixar a imutabilidade por causa dos benefícios já mencionados pela princesa Fluff . Deve ser uma exceção que algo seja mutável.
Infelizmente, a maioria das linguagens de programação atuais tem como padrão a mutabilidade, mas espero que no futuro o padrão seja mais a imutabilidade (consulte Uma lista de desejos para a próxima linguagem de programação mainstream ).
fonte
Uau! Não acredito na desinformação aqui.
String
ser imutável não tem nada com segurança. Se alguém já tiver acesso aos objetos em um aplicativo em execução (o que teria que ser assumido se você estivesse tentando se proteger contra alguém 'hackeando' umString
no seu aplicativo), certamente haveria muitas outras oportunidades disponíveis para hackers.É uma idéia bastante nova que a imutabilidade
String
está abordando problemas de segmentação. Hmmm ... Eu tenho um objeto que está sendo alterado por dois threads diferentes. Como eu resolvo isso? sincronizar o acesso ao objeto? Naawww ... não vamos deixar ninguém mudar o objeto - isso corrigirá todos os nossos problemas de concorrência desordenados! De fato, vamos tornar todos os objetos imutáveis e, em seguida, podemos remover o controle sincronizado da linguagem Java.O verdadeiro motivo (apontado por outros acima) é a otimização de memória. É bastante comum em qualquer aplicativo que a mesma string literal seja usada repetidamente. É tão comum, de fato, que décadas atrás, muitos compiladores fizeram a otimização de armazenar apenas uma única instância de um
String
literal. A desvantagem dessa otimização é que o código de tempo de execução que modifica umString
literal introduz um problema porque está modificando a instância para todos os outros códigos que o compartilham. Por exemplo, não seria bom para uma função em algum lugar de um aplicativo alterar oString
literal"dog"
para"cat"
. Aprintf("dog")
resultaria na"cat"
gravação em stdout. Por esse motivo, precisava haver uma maneira de se proteger contra códigos que tentam mudarString
literais (ou seja, torná-los imutáveis). Alguns compiladores (com suporte do sistema operacional) conseguiriam isso colocandoString
literalmente em um segmento de memória somente leitura especial que causaria uma falha na memória se fosse feita uma tentativa de gravação.Em Java, isso é conhecido como interning. O compilador Java aqui está apenas seguindo uma otimização de memória padrão feita por compiladores há décadas. E para resolver o mesmo problema desses
String
literais sendo modificados em tempo de execução, o Java simplesmente torna aString
classe imutável (ou seja, não fornece setters que permitam alterar oString
conteúdo).String
s não precisaria ser imutável se a internação deString
literais não ocorresse.fonte
String
eStringBuffer
, mas infelizmente poucos outros tipos seguem esse modelo.String
não é um tipo primitivo, mas você normalmente deseja usá-lo com semântica de valores, ou seja, como um valor.Um valor é algo em que você pode confiar não mudará pelas suas costas. Se você escrever:
String str = someExpr();
Você não quer que isso mude, a menos que você faça algostr
.String
como umaObject
semântica de ponteiro naturalmente, para obter semântica de valor, ela precisa ser imutável.fonte
Um fator é que, se
String
s forem mutáveis, os objetos que armazenamString
s terão que ter cuidado para armazenar cópias, para que seus dados internos não sejam alterados sem aviso prévio. Dado queString
s são um tipo bastante primitivo, como números, é bom quando se pode tratá-los como se fossem passados por valor, mesmo se passados por referência (o que também ajuda a economizar memória).fonte
Eu sei que isso é um inchaço, mas ... Eles são realmente imutáveis? Considere o seguinte.
...
Você pode até torná-lo um método de extensão.
O que faz o seguinte trabalho
Conclusão: Eles estão em um estado imutável, conhecido pelo compilador. É claro que o exposto acima se aplica apenas a seqüências .NET, pois o Java não possui ponteiros. No entanto, uma string pode ser totalmente mutável usando ponteiros em C #. Não é assim que os ponteiros devem ser usados, têm uso prático ou são usados com segurança; no entanto, é possível, dobrando assim toda a regra "mutável". Normalmente, você não pode modificar um índice diretamente de uma string e esse é o único caminho. Existe uma maneira de evitar isso, impedindo a ocorrência de instâncias de ponteiro ou fazendo uma cópia quando uma string é apontada, mas nenhuma delas é feita, o que torna as strings em C # não totalmente imutáveis.
fonte
Para a maioria dos propósitos, uma "string" é (usada / tratada como / considerada uma suposta) uma unidade atômica significativa , assim como um número .
Perguntar por que os caracteres individuais de uma string não são mutáveis é, portanto, como perguntar por que os bits individuais de um número inteiro não são mutáveis.
Você deveria saber o porquê. Apenas pense sobre isso.
Detesto dizer isso, mas infelizmente estamos debatendo isso porque nossa linguagem é péssima e estamos tentando usar uma única palavra, string , para descrever um conceito ou classe de objeto complexo e contextualmente situado.
Realizamos cálculos e comparações com "strings" semelhantes à forma como fazemos com números. Se strings (ou números inteiros) fossem mutáveis, teríamos que escrever um código especial para bloquear seus valores em formas locais imutáveis, a fim de realizar qualquer tipo de cálculo de maneira confiável. Portanto, é melhor pensar em uma sequência como um identificador numérico, mas, em vez de ter 16, 32 ou 64 bits, pode ter centenas de bits.
Quando alguém diz "string", todos pensamos em coisas diferentes. Aqueles que pensam nisso simplesmente como um conjunto de caracteres, sem nenhum objetivo específico em mente, ficarão horrorizados com o fato de alguém ter decidido que não deveria ser capaz de manipular esses caracteres. Mas a classe "string" não é apenas uma matriz de caracteres. É um
STRING
, não umchar[]
. Existem algumas suposições básicas sobre o conceito que chamamos de "string", e geralmente pode ser descrito como uma unidade atômica significativa de dados codificados, como um número. Quando as pessoas falam sobre "manipular strings", talvez estejam realmente falando sobre como manipular caracteres para criar strings , e um StringBuilder é ótimo para isso.Considere por um momento como seria se as cordas fossem mutáveis. A função de API a seguir pode ser induzida a retornar informações para um usuário diferente se a sequência de nome de usuário mutável for intencional ou não intencionalmente modificada por outro encadeamento enquanto esta função a estiver usando:
Segurança não é apenas sobre 'controle de acesso', é também sobre 'segurança' e 'garantia de correção'. Se um método não puder ser facilmente escrito e dependido para executar um cálculo simples ou uma comparação confiável, não é seguro chamá-lo, mas seria seguro questionar a própria linguagem de programação.
fonte
unsafe
) ou simplesmente através da reflexão (você pode obter o campo subjacente facilmente). Isso anula a questão da segurança, pois qualquer pessoa que queira alterar intencionalmente uma string pode fazê-lo facilmente. No entanto, fornece segurança aos programadores: a menos que você faça algo especial, a string é garantida imutável (mas não é segura para threads!).A imutabilidade não está tão intimamente ligada à segurança. Por isso, pelo menos no .NET, você obtém a
SecureString
classe.Edição posterior: em Java, você encontrará
GuardedString
uma implementação semelhante.fonte
A decisão de ter uma string mutável em C ++ causa muitos problemas, consulte este excelente artigo de Kelvin Henney sobre Mad COW Disease .
COW = Copiar na gravação.
fonte
É uma troca.
String
s entram noString
pool e quando você cria váriosString
s idênticos, eles compartilham a mesma memória. Os designers imaginaram que essa técnica de economia de memória funcionaria bem para o caso comum, já que os programas tendem a se desgastar muito pelas mesmas seqüências.A desvantagem é que as concatenações produzem muitos
String
s extras que são apenas transitórios e se tornam lixo, prejudicando o desempenho da memória. Você temStringBuffer
eStringBuilder
(em Java,StringBuilder
também está no .NET) para usar para preservar a memória nesses casos.fonte
String
s em Java não são realmente imutáveis, você pode alterar seus valores usando reflexão e / ou carregamento de classe. Você não deve depender dessa propriedade por segurança. Para exemplos, consulte: Truque de mágica em Javafonte
Imutabilidade é boa. Consulte Java efetivo. Se você tivesse que copiar uma String toda vez que a passasse, isso seria muito código propenso a erros. Você também tem confusão sobre quais modificações afetam quais referências. Da mesma maneira que o Inteiro precisa ser imutável para se comportar como int, as Strings precisam se comportar como imutáveis para agir como primitivas. No C ++, a passagem de cadeias por valor faz isso sem menção explícita no código-fonte.
fonte
Há uma exceção para quase quase todas as regras:
fonte
É principalmente por razões de segurança. É muito mais difícil proteger um sistema se você não pode confiar que seus sistemas
String
são à prova de violações.fonte