Por que String é imutável em Java?

177

Me perguntaram em uma entrevista por que String é imutável

Eu respondi assim:

Quando criamos uma string em java como String s1="hello";um objeto será criado no pool de strings (hello) e s1 apontará para hello. Agora, se fizermos novamente, String s2="hello";outro objeto não será criado, mas s2 apontará hello porque a JVM verificará primeiro se o mesmo objeto estiver presente no pool de cadeias ou não. Se não estiver presente, apenas um novo será criado.

Agora, se java suponha que permite mutável corda, em seguida, se mudarmos s1 para hello worldentão s2 valor também será hello worldassim java String é imutável.

Alguém pode me dizer se minha resposta está certa ou errada ?

balanço
fonte
46
Por que é sempre difícil responder. A resposta mais correta é provavelmente: porque os designers de linguagem acharam que era uma boa ideia.
Keppil
1
veja também, esta resposta
3
Sua resposta não está no ponto. C ++ std::stringé mutável, mas eles também possuem um conjunto de cadeias de caracteres (bem, mais corretamente, um conjunto de matrizes de caracteres).
Siyuan Ren 14/03
1
@rocking Para ser sincero, se é certo ou não, depende de como eles o leem. O problema é que o Java pode ter um conjunto de cadeias porque as cadeias são imutáveis. Se eles decidissem tornar as strings mutáveis, não teriam usado um pool de strings; portanto, pode não ser preciso dizer "pool de strings, portanto strings imutáveis"; é mais o contrário. Os motivos para a escolha de strings imutáveis ​​estão descritos abaixo e o pool de strings é uma estratégia de trabalho por causa disso. Ainda assim, sua resposta não está incorreta , apenas não parece completa. Você apenas terá que esperar e ver o que eles dizem.
Jason C
34
Simplesmente não consigo entender por que essa pergunta foi encerrada. A suposta resposta relacionada nem sequer é sobre Java e não aborda o assunto principal desta pergunta, que é "por que". Para mim, este é um daqueles casos de uma comunidade irresponsável, agindo sobre questões que eles desconhecem. Eu o nomeei para reabrir.
Edwin Dalorzo

Respostas:

163

String é imutável por várias razões, aqui está um resumo:

  • Segurança : os parâmetros normalmente são representados como Stringem conexões de rede, URLs de conexão de banco de dados, nomes de usuário / senhas etc. Se fossem mutáveis, esses parâmetros poderiam ser facilmente alterados.
  • Sincronização e simultaneidade: tornar o String imutável automaticamente torna o thread seguro, resolvendo os problemas de sincronização.
  • Armazenamento em cache : quando o compilador otimiza seus objetos String, ele vê que se dois objetos tiverem o mesmo valor (a = "test" eb = "test") e, portanto, você precisará de apenas um objeto string (para ambos a e b, esses dois serão aponte para o mesmo objeto).
  • Carregamento de classe : Stringé usado como argumento para carregamento de classe. Se mutável, pode resultar no carregamento incorreto da classe (porque objetos mutáveis ​​alteram seu estado).

Dito isto, a imutabilidade Stringsignifica apenas que você não pode alterá-lo usando sua API pública. Na verdade, você pode ignorar a API normal usando reflexão. Veja a resposta aqui .

No seu exemplo, se Stringera mutável, considere o seguinte exemplo:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow
Comunidade
fonte
14
Como isso poderia afetar a segurança?
Archit Maheshwari
2
Alguém pode explicar o carregamento da classe com um exemplo, se possível?
Viraj
6
No que diz respeito à segurança, se estou interessado em alterar os parâmetros de conexão, é direto no tempo de execução (com um depurador, etc.). Em relação ao carregamento de classe, se Stringfor mutável, o carregador de classes pegará a string passada, fará uma cópia e não alterará sua cópia. Ao pensar em um problema com mutáveis java.lang.Strings, pense em como resolve C ++ este problema (uma vez que tem mutáveis std::strings.
Expiação Limitada
Em relação à segurança, como uma sequência mutável pode ser alterada quando o programa está sendo executado?
MasterJoe2
Como String é imutável, seu código de hash é armazenado em cache no momento da criação e não precisa ser calculado novamente.
Abdul Alim Shakir,
45

Os desenvolvedores de Java decidem que as strings são imutáveis ​​devido ao seguinte aspecto , design, eficiência e segurança .

As seqüências de design são criadas em uma área de memória especial na pilha java conhecida como "Conjunto de String Intern". Enquanto você cria um novo String (não no caso de usar o construtor String () ou qualquer outra função String que use internamente o construtor String () para criar um novo objeto String; o construtor String () sempre cria uma nova constante de string no pool, a menos que chame a variável intern () do método que ele procura no pool para verificar se ele já existe. Se existir, retorne a referência do objeto String existente. Se a String não for imutável, alterar a String com uma referência levará ao valor errado para as outras referências.

De acordo com este artigo no DZone:

O Security String é amplamente utilizado como parâmetro para muitas classes java, por exemplo, conexão de rede, abertura de arquivos, etc. Se o String não for imutável, uma conexão ou arquivo será alterado e levará a sérias ameaças à segurança. Strings mutáveis ​​também podem causar problemas de segurança no Reflection, pois os parâmetros são strings.

Eficiência O código de hash da cadeia de caracteres é frequentemente usado em Java. Por exemplo, em um HashMap. Ser imutável garante que o hashcode sempre será o mesmo, para que possa ser armazenado em cache sem preocupar-se com as alterações. Isso significa que não há necessidade de calcular o hashcode sempre que for usado.

Alex Mathew
fonte
7
Seu entendimento do pool de strings está incorreto. As constantes de string são criadas no pool interno, mas é perfeitamente possível ter mais de um objeto de string com o mesmo texto. Concordo que as strings imutáveis ​​permitem o pool, mas não há tanto pool que você declarou.
Jon Skeet
@ JonSkeet Você está certo. String s1 = new String ("teste"); A instrução create new string constant no pool interno, a menos que chamemos o método intern (). Obrigado por aprofundar meu conhecimento sobre o pool interno de strings.
Alex Mathew
2
É mais do que apenas usar o construtor de strings - quase qualquer coisa que crie uma nova string, por exemplo, substring, split, concat etc criará novas strings. As constantes de tempo de compilação são o caso especial aqui, não a norma ...
Jon Skeet
@JonSkeet substring (), concat (), replace () etc são usados ​​internamente no construtor String para criar um novo objeto string. Obrigado por melhorar minha resposta.
Alex Mathew
2
@ JonSkeet - Todas essas respostas dizem que a imutabilidade melhora a "segurança", mas não explica como. Todos eles apontam para um artigo vago do dzone que também não ajuda. As respostas / link não explicam como uma sequência mutável pode ser alterada quando o código está em execução. Você poderia explicar?
MasterJoe2
25

Não podemos ter certeza do que os designers de Java estavam realmente pensando ao projetar, Stringmas podemos concluir esses motivos com base nas vantagens que obtemos da imutabilidade de cadeias de caracteres, algumas das quais são

1. Existência de pool constante de strings

Conforme discutido no artigo Por que a seqüência de caracteres é armazenada no pool constante de seqüências de caracteres , todo aplicativo cria muitos objetos de sequência e, a fim de salvar a JVM primeiro criando muitos objetos de sequência e depois coletando-os com lixo. A JVM armazena todos os objetos de sequência em uma área de memória separada chamada Conjunto constante de sequência e reutiliza objetos desse conjunto em cache.

Sempre que criamos um literal de cadeia, a JVM vê pela primeira vez se esse literal já está presente no pool constante ou não, e se existe, uma nova referência começará a apontar para o mesmo objeto no SCP.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

No exemplo acima objeto string com o valor Nareshirá ser criada no SCP apenas uma vez e todas as referências a, b, cirá apontar para o mesmo objeto, mas o que se tentarmos fazer a mudança em aeg a.replace("a", "").

Idealmente, adeve ter valor , Nreshmas deve permanecer inalterado porque, como usuário final, estamos fazendo apenas a alteração . E sabemos , , todos estão apontando o mesmo objeto para se fazer uma mudança em , outros também devem refletir a alteração.bcaabca

Mas a imutabilidade de string nos salva desse cenário e, devido à imutabilidade do objeto de string, o objeto de string Nareshnunca será alterado. Portanto, quando fazemos alguma alteração no aobjeto de sequência, em vez de no NareshJVM, um novo objeto é atribuído ae, então, fazemos a alteração nesse objeto.

Portanto, o pool de String só é possível devido à imutabilidade de String e se String não fosse imutável, o armazenamento em cache de objetos de string e a sua reutilização não teriam possibilidade, porque qualquer variável alteraria o valor e corromperia outros.

E é por isso que é tratado pela JVM de maneira muito especial e recebeu uma área de memória especial.

2. Segurança da linha

Um objeto é chamado de thread-safe quando vários threads estão operando nele, mas nenhum deles pode corromper seu estado e o objeto mantém o mesmo estado para todos os threads a qualquer momento.

Como nós, um objeto imutável não pode ser modificado por ninguém após sua criação, o que torna todos os objetos imutáveis ​​protegidos por thread por padrão. Não precisamos aplicar nenhuma medida de segurança de thread, como a criação de métodos sincronizados.

Portanto, devido à sua natureza imutável, o objeto string pode ser compartilhado por vários threads e, mesmo que esteja sendo manipulado por muitos threads, não alterará seu valor.

3. Segurança

Em todas as aplicações, precisamos passar vários segredos, por exemplo, nome de usuário \ senhas do usuário, URLs de conexão e, em geral, todas essas informações são passadas como o objeto string.

Agora, suponha que se String não fosse imutável por natureza, isso causaria uma séria ameaça à segurança do aplicativo, porque esses valores podem ser alterados e, se for permitido, podem ser alterados devido a códigos escritos incorretamente ou a qualquer outra pessoa que tenha acesso às nossas referências de variáveis.

4. Carregamento de classe

Conforme discutido em Criando objetos através do Reflection em Java com exemplo , podemos usar o Class.forName("class_name")método para carregar uma classe na memória que novamente chama outros métodos para fazê-lo. E até a JVM usa esses métodos para carregar classes.

Mas se você ver claramente todos esses métodos aceitam o nome da classe como um objeto string, portanto, Strings são usadas no carregamento da classe java e a imutabilidade fornece segurança pela qual a classe correta está sendo carregada ClassLoader.

Suponha que se String não fosse imutável e estamos tentando carregar os java.lang.Objectque foram alterados para org.theft.OurObjectentre e agora todos os nossos objetos têm um comportamento que alguém pode usar para coisas indesejadas.

5. Cache de HashCode

Se pretendemos executar operações relacionadas a hash em qualquer objeto, devemos substituir o hashCode()método e tentar gerar um código de hash preciso usando o estado do objeto. Se o estado de um objeto está sendo alterado, significa que seu código de hash também deve mudar.

Como String é imutável, o valor que um objeto de string está mantendo nunca será alterado, o que significa que seu código de hash também não será alterado, o que dá à classe String uma oportunidade de armazenar em cache seu código de hash durante a criação do objeto.

Sim, o objeto String armazena em cache seu código de hash no momento da criação do objeto, o que o torna o melhor candidato para operações relacionadas ao hash, porque o código de hash não precisa ser calculado novamente, o que economiza algum tempo. É por isso que String é usado principalmente como HashMapchaves.

Leia mais sobre Por que a string é imutável e final em Java .

Naresh Joshi
fonte
1
Em relação à segurança - Como o valor da sequência mutável pode ser alterado na memória? Como outra pessoa pode ter acesso às nossas referências de variáveis?
25418 MasterJoe2
Não se trata de como se pode ter acesso às referências; e se alguém tiver acesso a essas? como mencionado "se a String não fosse imutável por natureza, isso causaria uma séria ameaça à segurança do aplicativo, porque esses valores podem ser alterados e, se for permitido, podem ser alterados devido a códigos escritos incorretamente ou a qualquer outra pessoa. que têm acesso às nossas referências de variáveis ​​".
Naresh Joshi
O como importa aqui. É possível obter acesso às referências ou não. Se possível, você pode citar 1-2 técnicas *** (ou seja, como) que podem ser usadas para isso? Se não for possível, o ponto sobre segurança não é aplicável. *** Exemplo - Nomeie uma técnica para atacar o banco de dados de um aplicativo Web -> Injeção de SQL. Você conhece alguma técnica como esta para atacar as referências?
MasterJoe2
Como mencionado, "Isso pode acontecer devido a código escrito incorretamente ou a qualquer alteração feita por outra pessoa que tenha acesso às nossas referências de variáveis". Por exemplo, suponha que String seja mutável e você esteja escrevendo algum método que esteja usando uma string como um segredo de string e, novamente, essa string seja passada para vários outros métodos no meio e um desses métodos não seja gravado por você e esse método fez algumas alterações nesse Agora, após chamar todos esses métodos, o controle retornou seu método e você está usando essa sequência novamente, mas ela foi alterada.
Naresh Joshi
2
Divulgue quaisquer afiliações e não use o site como forma de promover seu site através da publicação. Consulte Como escrevo uma boa resposta? .
Yvette - Restabelece Monica
21

Razão mais importante de acordo com este artigo no DZone:

Pool constante de strings ... Se o strings é mutável, alterar o string com uma referência levará ao valor errado para as outras referências.

Segurança

String é amplamente utilizado como parâmetro para muitas classes java, por exemplo, conexão de rede, abertura de arquivos, etc. Se a String não for imutável, uma conexão ou arquivo será alterado e levará a sérias ameaças à segurança. ...

Espero que ajude você.

JDGuide
fonte
@JasonC Eu só quero saber se a minha resposta está errada ou não. Eu já participei da entrevista e aguardo o resultado. Se a resposta for correta, então eu serei selecionado
arrasando em
1
Segundo meu conhecimento, sua resposta está correta, mas imutável significa que a referência nunca será alterada no local do apontador. Tudo de bom para sua entrevista.
JDGuide
1
Se aceitar o seu ponto 1, todos os objetos devem ser imutáveis.
Nicomp
Olá JDeveloper, editei sua resposta para atribuir a fonte correta da fonte. Lembre-se de sempre usar aspas para cópias textuais do conteúdo. Obrigado!
61117 NickL
O artigo DZone contém grandes erros sobre a operação do pool Strign. É apenas para constantes. Portanto, a lógica declarada é inválida.
Marquês de Lorne
4

Li este post Por que a String é imutável ou final em Java e suponho que o seguinte seja o motivo mais importante:

String é Imutável em Java porque os objetos String são armazenados em cache no pool de String . Como os literais de String em cache são compartilhados entre vários clientes, há sempre um risco, em que a ação de um cliente afetaria todos os outros clientes.

Tho
fonte
1

Você está certo. Stringem java usa o conceito de String Poolliteral. Quando uma string é criada e se a string já existe no pool, a referência da string existente será retornada, em vez de criar um novo objeto e retornar sua referência.Se uma string não for imutável, alterar a string com uma referência será levar ao valor errado para as outras referências.

Eu acrescentaria mais uma coisa, já que Stringé imutável, é seguro para multi-threading e uma única instância de String pode ser compartilhada em diferentes segmentos. Isso evita o uso da sincronização para segurança do encadeamento. As seqüências são implicitamente thread safe.

Akshay
fonte
0

Classe de string FINALsignifica que você não pode criar nenhuma classe para herdá-la, alterar a estrutura básica e tornar o Sting mutável.

Outra variável de instância e métodos da classe String fornecidos são tais que você não pode alterar o Stringobjeto depois de criado.

O motivo pelo qual você adicionou não torna a String imutável.Tudo indica como a String é armazenada na pilha.Também o pool de strings faz a enorme diferença no desempenho

Pontapé
fonte
11
Se a classe for declarada como final, significa que a classe não pode ser herdada, mas isso não significa que os campos de instâncias da classe não podem ser alterados e, portanto, a classe é imutável.
Dmitry Bychenko
@ Zeeshan: As classes de exemplo que você dá são todas imutáveis.
Siyuan Ren 14/03
0

A string é fornecida como imutável pelos microssistemas Sun, porque a string pode ser usada para armazenar como chave na coleção de mapas. StringBuffer é mutável. Esse é o motivo, não pode ser usado como chave no objeto de mapa

chaithanya krishna gogineni
fonte
0

O motivo mais importante de uma String ser imutável em Java é a consideração de segurança . Em seguida seria o cache .

Acredito que outras razões apresentadas aqui, como eficiência, concorrência, design e pool de strings, decorram do fato de que String se tornou imutável. Por exemplo. O pool de strings pode ser criado porque o String é imutável e não o contrário.

Confira a transcrição da entrevista de Gosling aqui

Do ponto de vista estratégico, eles tendem a estar mais livres de problemas. E geralmente existem coisas que você pode fazer com imutáveis ​​que você não pode fazer com coisas mutáveis, como armazenar o resultado em cache. Se você passar uma string para um método de arquivo aberto ou se você passar uma string para um construtor para um rótulo em uma interface de usuário, em algumas APIs (como em muitas APIs do Windows), você passará uma matriz de caracteres. O receptor desse objeto realmente precisa copiá-lo, porque eles não sabem nada sobre a vida útil do armazenamento. E eles não sabem o que está acontecendo com o objeto, se está sendo alterado sob seus pés.

Você acaba sendo quase forçado a replicar o objeto porque não sabe se o possui ou não. E uma das coisas boas sobre objetos imutáveis ​​é que a resposta é: "Sim, claro que sim". Porque a questão da propriedade, que tem o direito de alterá-la, não existe.

Uma das coisas que forçaram o Strings a ser imutável foi a segurança. Você tem um método de abertura de arquivo. Você passa uma String para ele. E, em seguida, realiza todos os tipos de verificações de autenticação antes de fazer a chamada do SO. Se você conseguir fazer algo que modifique efetivamente a String, após a verificação de segurança e antes da chamada do sistema operacional, faça o boom. Você entrará. Mas as Strings são imutáveis, para que esse tipo de ataque não funcione. Esse exemplo preciso é o que realmente exigia que as Strings fossem imutáveis

Sameer Sinha
fonte
0

Além das ótimas respostas, gostaria de acrescentar alguns pontos. Como Strings, Array mantém uma referência ao início da matriz, portanto, se você criar duas matrizes arr1e arr2fez algo parecido com arr2 = arr1isso, a referência será a arr2mesma, pois a arr1alteração do valor em uma delas resultará na alteração da outra, por exemplo

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

Além de causar bugs no código, ele também pode (e será) explorado por usuários mal-intencionados. Suponha que você tenha um sistema que altere a senha do administrador. O usuário deve primeiro digitar o newPassworde, em seguida, oldPasswordse o oldPasswordmesmo for adminPasso programa, altere a senha adminPass = newPassword. digamos que a nova senha tenha a mesma referência que a senha de administrador, portanto, um programador ruim pode criar uma tempvariável para reter a senha de administrador antes que os usuários insiram dados se o valor oldPasswordigual a tempele alterar a senha, caso contrárioadminPass = temp. Alguém sabendo que poderia facilmente inserir a nova senha e nunca inserir a senha antiga e abracadabra, ele tem acesso de administrador. Outra coisa que eu não entendi ao aprender sobre Strings, por que a JVM não cria uma nova string para cada objeto e tem um lugar único na memória para isso? Você pode fazer isso usando new String("str");O motivo pelo qual você não gostaria de usar sempre newé porque não é eficiente em termos de memória e é mais lento na maioria dos casos, leia mais .

Qeaxe
fonte
0

Se HELLOé sua String, você não pode mudar HELLOpara HILLO. Essa propriedade é chamada propriedade de imutabilidade.

Você pode ter várias variáveis ​​String de ponteiro para apontar HELLO String.

Mas se HELLO for char Array, você poderá alterar HELLO para HILLO. Por exemplo,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

Responda:

As linguagens de programação possuem variáveis ​​de dados imutáveis, para que possam ser usadas como chaves no par de chaves e valores. Variáveis ​​de string são usadas como chaves / índices, portanto são imutáveis .

Uddhav Gautam
fonte
-1

Do Securityponto de vista, podemos usar este exemplo prático:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}
darxtrix
fonte