Pergunta

Por que é que eles decidiram fazer imutável corda em Java e .NET (e algumas outras línguas)? Por que não torná-lo mutável?

Foi útil?

Solução

De acordo com a 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 design, implementar e usar do que as classes mutáveis. Eles são menos propensos de erro e são mais seguros.

[...]

" Objetos imutáveis ??são simples. Um objeto imutável pode estar em exatamente um estado, o estado em que ele foi criado. Se você se certificar que todos os construtores estabelecer invariantes de classe, então é a garantia de que esses invariantes permanecerá verdadeiro para todos os tempos, com nenhum esforço de sua parte.

[...]

Objetos imutáveis ??são inerentemente thread-safe; eles não necessitam de sincronização. Eles podem não ser corrompido por vários segmentos acessá-los simultaneamente. Este é, de longe, a abordagem mais fácil para alcançar a segurança do thread. Na verdade, nenhuma outra thread pode sempre observar qualquer Efeito do outro segmento em um objeto imutável. Portanto, objetos imutáveis ??podem ser compartilhados livremente

[...]

Outros pequenos pontos do mesmo capítulo:

Não só você pode compartilhar objetos imutáveis, mas você pode compartilhar seus internos.

[...]

Objetos imutáveis ??fazer grandes blocos de construção para outros objetos, sejam mutáveis ??ou imutáveis.

[...]

A desvantagem única real de classes imutáveis ??é que eles exigem um objeto separado para cada valor distinto.

Outras dicas

Há pelo menos duas razões.

Primeiro - segurança http://www.javafaq.nu/ java-article1060.html

A principal razão da corda feita imutável era a segurança. Veja isso exemplo: Nós temos um método aberto de arquivo com verificação de login. Nós passar uma String para este método para autenticação processo que é necessário antes da chamada será passado para OS. Se cadeia foi mutável, foi possível alguma forma de modificar o seu conteúdo após o verificação de autenticação antes OS recebe pedido do programa, então é possível solicitar qualquer arquivo. Então se você tem o direito de arquivo de texto aberto diretório do usuário, mas, em seguida, on the fly quando de alguma forma você consegue mudar o nome do arquivo que você pode pedir para abrir "Passwd" arquivo ou qualquer outro. Então uma arquivo pode ser modificado e será possível entrar diretamente para OS.

Em segundo lugar - a eficiência da memória http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

JVM mantém internamente o "String Pool". Para achive a memória eficiência, JVM irá se referir String objeto da piscina. Não criará o novo objetos String. Assim, sempre que você cria um novo literal de cadeia, JVM irá verificar na piscina se já existe ou não. Se já presente na piscina, apenas dar o referência para o mesmo objecto ou criar o novo objeto na piscina. Haverá ser muitas referências apontam para o mesmo Objetos String, se alguém muda a valor, que irá afectar toda a referências. Então, sol decidiu torná-lo imutável.

Na verdade, a corda razões são imutáveis ??em Java não tem muito a ver com segurança. As duas razões principais são as seguintes:

thead Segurança:

Strings são extremamente amplamente utilizado tipo de objeto. É, por conseguinte, mais ou menos garantida para ser usado em um ambiente multi-threaded. Strings são imutáveis ??para se certificar de que é seguro para cordas ações entre threads. Ter um cordas imutáveis ??garante que ao passar cordas de fio de à outro segmento B, linha B pode não inesperadamente modificar corda fio de A.

Isto não só ajuda a simplificar a tarefa já bastante complicado de programação multi-thread, mas também ajuda com o desempenho de aplicações multi-threaded. Acesso a objetos mutáveis ??deve de alguma forma ser sincronizados quando eles podem ser acessados ??a partir de vários segmentos, para se certificar de que um segmento não tentar ler o valor de seu objeto enquanto ele está sendo modificado por outro segmento. sincronização adequada é ao mesmo tempo difícil de fazer corretamente para o programador, e caro em tempo de execução. objetos imutáveis ??não podem ser modificados e, portanto, não precisa de sincronização.

Performance:

Enquanto Cordas Internar foi mencionado, isso representa apenas um pequeno ganho de eficiência da memória para programas Java. Somente strings literais estão internados. Isso significa que apenas as cordas que são as mesmas em sua código-fonte irá compartilhar o mesmo objeto String. Se o seu programa cria dinamicamente cadeia que são os mesmos, eles serão representados em diferentes objetos.

Mais importante, cordas imutáveis ??permitir que eles compartilhem seus dados internos. Para muitas operações de cadeia, isso significa que a matriz subjacente de caracteres não precisa ser copiado. Por exemplo, digamos que você quer tomar os cinco primeiros caracteres da cadeia. Em Java, você faria chamadas myString.substring (0,5). Neste caso, o que o método substring () faz é simplesmente criar um novo objeto String que caractere subjacente ações da myString [], mas que sabe que ele começa no índice 0 e termina no índice 5 do mesmo char []. Para colocar isso em forma gráfica, você iria acabar com o seguinte:

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

Isso faz com que este tipo de operações extremamente barato, e O (1) desde que a operação não depende do comprimento da corda original, nem sobre o comprimento do substring precisamos extrato. Esse comportamento também tem alguns benefícios de memória, uma vez que muitas cordas podem compartilhar seu carvão subjacente [].

Segmento de segurança e desempenho. Se a cadeia não pode ser modificado é seguro e rápido para passar uma referência ao redor entre vários segmentos. Se cordas eram mutáveis, você sempre tem que copiar todos os bytes da string para uma nova instância, ou fornecer sincronização. Uma aplicação típica irá ler uma string de 100 vezes para cada vez que as necessidades de cordas a ser modificado. Veja wikipedia sobre imutabilidade .

Um realmente deve perguntar, "por que X ser mutável?" É melhor para o padrão para imutabilidade, por causa dos benefícios já mencionados por Princess Fluff . Ele deve ser uma exceção que algo é mutável.

Infelizmente a maior parte do atual padrão linguagens de programação para mutabilidade, mas espero que no futuro o padrão é mais em immutablity (veja a lista de desejos para o próximo Mainstream linguagem de programação ).

Um fator é que, se cordas eram mutáveis, objetos armazenar cordas teria que ter o cuidado de armazenar cópias, para que sua mudança interna de dados sem aviso prévio. Dado que as cordas são um tipo bastante primitiva como números, é bom quando se pode tratá-los como se fossem passados ??por valor, mesmo se eles são passados ??por referência (que também ajuda a economizar em memória).

Wow! Eu não acredito que a desinformação aqui. Cordas ser imutável não tem nada com segurança. Se alguém já tem acesso aos objetos em um aplicativo em execução (que teriam de ser assumido, se você está tentando se proteger contra alguém 'hackers' uma String em seu aplicativo), que seria certamente uma abundância de outras oportunidades disponíveis para hacking.

É um muito romance idéia de que a imutabilidade da String é abordar questões Threading. Hmmm ... Eu tenho um objeto que está sendo alterado por dois tópicos diferentes. Como posso resolver isso? sincronizar o acesso ao objeto? Naawww ... não vamos deixar ninguém mudança do objeto em tudo - que vai corrigir todos os nossos problemas de concorrência desarrumado! Na verdade, vamos fazer todos os objetos imutáveis, e então nós podemos removeu o contruct synchonized da linguagem Java.

A razão real (apontado por outros acima) é a otimização de memória. É bastante comum em qualquer aplicação para o mesmo literal string para ser usado repetidamente. É tão comum, de fato, que décadas atrás, muitos compiladores feita a otimização de armazenar apenas uma única instância de um literal string. A desvantagem desta otimização é que o código de tempo de execução que modifica um cordas introduz literais um problema porque ele está modificando a instância para todos outro código que compartilha. Por exemplo, seria não é bom para um lugar de função em um aplicativo para mudar a string literal "cão" para "gato". A printf ( "cão") resultaria em "gato" sendo escrito na saída padrão. Por essa razão, é preciso haver uma forma de se proteger contra código que tenta strings literais mudança (i. E., Torná-los imutáveis). Alguns compiladores (com o apoio do OS) iria conseguir isso colocando literal cadeia de caracteres em um segmento de memória somente leitura especial que poderia causar uma falha de memória, se uma tentativa de gravação foi feita.

Em Java isso é conhecido como internar. O compilador Java aqui está apenas seguindo uma otimização de memória padrão feito por compiladores por décadas. E para resolver o mesmo problema destes strings literais sendo modificado em tempo de execução, Java simplesmente faz o imutável classe String (i. E, dá-lhe há setters que lhe permitem alterar o conteúdo String). Cordas não teria que ser imutável se internar de strings literais não ocorreu.

string não é um tipo primitivo, mas você normalmente quer usá-lo com valores semânticos, ou seja, como um valor.

Um valor é algo que você pode confiar não mudará atrás das costas. Se você escrever: String str = someExpr(); Você não quer que ele mude a menos que você faça alguma coisa com str.

String como um objeto tem semântica naturalmente ponteiro, para obter valores semânticos bem ele precisa ser imutável.

Eu sei que isto é um galo, mas ... eles são realmente imutáveis? Considere o seguinte.

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

Você pode até mesmo torná-lo um método de extensão.

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

O que faz o trabalho seguinte

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

Conclusão: Eles estão em um estado imutável, que é conhecido pelo compilador. De couse acima só se aplica a .NET cordas como Java não tem ponteiros. No entanto, uma corda pode ser totalmente mutável usando ponteiros em C #. Não é como ponteiros se destinam a ser utilizados, tem uso prático ou é usado com segurança; é no entanto possível, dobrando, assim, toda a regra "mutável". Você normalmente não pode modificar um índice diretamente de uma corda e este é o único caminho. Há uma maneira que isso poderia ser evitado por não permitindo casos ponteiro de cordas ou fazer uma cópia quando uma string é apontado, mas também não é feito, o que torna cordas em C # não é totalmente imutável.

Na maioria dos casos, uma "string" é (usado / tratado como / pensamento de / assumido ser) um unidade significativa atômica, apenas como um número .

Perguntando porque os caracteres individuais de uma string não são mutáveis ??é, portanto, como perguntar por que os pedaços individuais de um inteiro não são mutáveis.

Você deve saber o porquê. Basta pensar nisso.

Eu odeio dizer isso, mas infelizmente estamos debatendo isso porque a nossa língua é uma porcaria, e nós estamos tentando usar uma única palavra, string , para descrever um, contextualmente situado conceito complexo ou classe de objeto.

Nós realizar cálculos e comparações com "strings" semelhante à forma como fazemos com números. Se strings (ou inteiros) foram mutável, nós teríamos que escrever código especial para bloquear os seus valores em formas locais imutáveis, a fim de realizar qualquer tipo de cálculo de forma confiável. Portanto, é melhor pensar em uma string como um identificador numérico, mas em vez de ser 16, 32 ou 64 bits de comprimento, poderia ser centenas de bits de comprimento.

Quando alguém diz "string", todos nós pensamos de coisas diferentes. Aqueles que pensam dele simplesmente como um conjunto de caracteres, com nenhum propósito específico em mente, será naturalmente chocado que alguém apenas decidi que não deve ser capaz de manipular esses caracteres. Mas a classe "string" não é apenas um conjunto de caracteres. É um STRING, não um char[]. Existem alguns pressupostos básicos sobre o conceito que nos referimos como uma "string", e geralmente pode ser descrito como unidade significativa, atômico de dados codificados como um número. Quando as pessoas falam sobre "cordas manipulação", talvez eles estão realmente falando sobre manipular caracteres para construir cordas , e um StringBuilder é ótimo para isso. Basta pensar um pouco sobre o que a palavra "string" realmente significa.

Considere por um momento o que seria como se cordas eram mutável. A função API seguinte poderia ser enganado e informações de retornar para um usuário diferente se o mutável string nome de usuário é intencionalmente ou não modificado por outro thread enquanto esta função estiver usando-o:

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 );
    }
}

A segurança não é apenas sobre 'controle de acesso', é também sobre a 'segurança' e 'garantir a correção'. Se um método não pode ser facilmente escritas e dependia para executar um cálculo simples ou comparação de forma confiável, então não é seguro para chamá-lo, mas seria seguro para pôr em causa a própria linguagem de programação.

A imutabilidade não é tão intimamente ligada à segurança. Para isso, pelo menos em .NET, você começa a classe SecureString.

É um trade off. Cordas para entrar na piscina corda e quando você cria várias cadeias idênticas eles compartilham a mesma memória. Os designers descobriram isso salvando técnica iria funcionar bem para o caso comum de memória, uma vez que os programas tendem a moer sobre os mesmos cordas muito.

A desvantagem é que concatenations fazer um monte de cordas extras que são lixo única transição e acaba de se tornar, de fato prejudicando o desempenho da memória. Você tem StringBuffer e StringBuilder (em Java, StringBuilder é também na NET) para usar para preservar a memória nestes casos.

A decisão de ter mutável string em C ++ provoca uma série de problemas, consulte este excelente artigo de Kelvin Henney sobre doença das vacas loucas .

COW = cópia na escrita.

Strings em Java não são verdadeiramente imutável, você pode alterar usando o reflexo do seu valor e ou carregamento de classe. Você não deve ser, dependendo do que a propriedade para a segurança. Para exemplos, veja: Truque de Magia Em Java

A imutabilidade é bom. Veja Effective Java. Se você tivesse que copiar uma cadeia cada vez que você passou-o, então, que seria um monte de código propenso a erros. Você também tem confusão sobre qual modificações afetam as referências. Da mesma forma que Integer tem que ser imutável a se comportar como int, Cordas tem que se comportar como imutável a agir como primitivos. Em C ++ passando cordas por valor faz isso sem menção explícita no código-fonte.

Há uma exceção para quase quase todas as regras:

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();
            }
        }
    }
}

É em grande parte por razões de segurança. É muito mais difícil de garantir um sistema se você não pode confiar em que as cordas são à prova de violação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top