Pra que tanta complicação para explicar a imutabilidade de String?

16 respostas
MrDataFlex

o livro da khaty aborda quase um capítulo para explicar isso:

não bastasse dizer que:

Quando se faz, assim:

  1. minhaString = “valor”; // ma verdade vc está fazendo (mas implicitamente) assim: minhaString = new String(“valor”);

  2. obviamente que, seguindo a regra de referencias:

  3. minhaNovaString = minhaString … ambas terão o valor de: “valor” …

MAS, quando vc faz: minhaNovaString = “novoValor” VOCÊ NÃO MODIFICA O VALOR, E SIM A REFERENCIA, VOLTANDO AO ITEM 1), OU SEJA, CRIANDO UM NOVO OBJETO E REFERENCIANDO-O, E NÃO ALTERANDO A REFERENCIA.

logo, para entender bem, sem complicações, ou considerações de que String é um Super-Hiper-Tri Objeto Especial, basta olhar a atribuição de valores a String como sendo na verdade um new explicito!

16 Respostas

blackout

Precisa ficar bravo por causa disso? Relaxa, rsrs

Alexandre_Saudate

Na verdade…

O q se tem não é um new… digamos assim:

Toda string que se cria é armazenada em posições de memória. Assim, se você tiver:

minhaString = “um”

minhaOutraString = “um”

elas apontarão para a MESMA posição de memória. E é isso que é complicado de explicar.

Rafael_Nunes

E nao necessariamente ele implicitamente fazer uma chamada a new String.

Tanto que?

String x = String;

String y = new String(String);

String z = String;

x e y sao referencias para objetos diferentes.
x e z apontam para o mesmo objeto no pool de strings.

blackout

asaudate:
Na verdade…

O q se tem não é um new… digamos assim:

Toda string que se cria é armazenada em posições de memória. Assim, se você tiver:

minhaString = “um”

minhaOutraString = “um”

elas apontarão para a MESMA posição de memória. E é isso que é complicado de explicar.

Na verdade elas apontariam pra MESMA posição de memória se fosse:

minhaString = "um"
minhaOutraString = minhaString

Mas do jeito que você está falando. Seriam posições de memórias diferentes, pois apesar de colocar “um” nas duas variaveis, uma não tem nada a ver com a outra.

Me corrijam se eu estiver errado, mas acho que é isso.

ziegfried

Você está um pouco enganado quando diz que a atribuição de valores é um new String implícito, meu caro. Nem sempre é assim.

Na atribuição (String s = “valor”), o pool de Strings interno da JVM é varrido para ver se o string atribuído está na memória. Se estiver, ele é reaproveitado para a nova variável (economizando memória). Se não, um novo objeto String é instanciado e adicionado ao pool.

Já na instanciação (String s = new String(“valor”)), sempre um novo objeto é criado. Ou seja, não é feita a verificação para ver se ele está na memória.

blackout

ziegfried:
Você está um pouco enganado quando diz que a atribuição de valores é um new String implícito, meu caro. Nem sempre é assim.

Na atribuição (String s = “valor”), o pool de Strings interno da JVM é varrido para ver se o string atribuído está na memória. Se estiver, ele é reaproveitado para a nova variável (economizando memória). Se não, um novo objeto String é instanciado e adicionado ao pool.

Já na instanciação (String s = new String(“valor”)), sempre um novo objeto é criado. Ou seja, não é feita a verificação para ver se ele está na memória.

Hummm, isso eu não sabia, então desconsiderem o que eu disse acima. Realmente aquilo que eu disse está equivocado. Desculpem!!!

L

blackout:
asaudate:
Na verdade…

O q se tem não é um new… digamos assim:

Toda string que se cria é armazenada em posições de memória. Assim, se você tiver:

minhaString = “um”

minhaOutraString = “um”

elas apontarão para a MESMA posição de memória. E é isso que é complicado de explicar.

Na verdade elas apontariam pra MESMA posição de memória se fosse:

minhaString = "um"
minhaOutraString = minhaString

Mas do jeito que você está falando. Seriam posições de memórias diferentes, pois apesar de colocar “um” nas duas variaveis, uma não tem nada a ver com a outra.

Me corrijam se eu estiver errado, mas acho que é isso.

Você está errado.

A resposta acima da sua do Rafael Nunes explica isso.

De um modo bem grosseiro, quando vc faz um:

String x = "Java"

O Java vai em um pool de String procurar se já existe uma string “Java” na memória. Se já existir, ele vai te dar a referência para ela, senão vai te criar uma nova.

De um modo grosseiro é isso. Mas existem vários conceitos mais avançados por de trás disso.

lgi2020

É como o amigo acima falou:

Toda String em Java, independente se for criada com new, ou numa atribuição, ou numa concatenação, é armazenada em um local espcial: o pool de Strings.

Dessa forma, temos o seguinte:

System.out.println("testando..."); //aqui se cria a String no pool de Strings. Não há objetos referenciando a String. String teste1 = "testando..."; //como esta String já existe, faz referência à String que já está no pool. 1 Objeto referenciando essa String. String teste2 = new String("testando..."); //2 Objetos referenciando a mesma String.

Se as Strings pudessem ser alteradas, você teria referências inconsistentes, já que vários Objetos sem qualquer ligação acessa a mesma String no pool.

Espero ter ajudado.

Abraços.

blackout

Sim sim, eu já tinha percebido que eu estava errado.

Mas mesmo assim vlw.

maquiavelbona

lgi2020:
É como o amigo acima falou:

Toda String em Java, independente se for criada com new, ou numa atribuição, ou numa concatenação, é armazenada em um local espcial: o pool de Strings.

Dessa forma, temos o seguinte:

System.out.println("testando..."); //aqui se cria a String no pool de Strings. Não há objetos referenciando a String. String teste1 = "testando..."; //como esta String já existe, faz referência à String que já está no pool. 1 Objeto referenciando essa String. String teste2 = new String("testando..."); //2 Objetos referenciando a mesma String.

Se as Strings pudessem ser alteradas, você teria referências inconsistentes, já que vários Objetos sem qualquer ligação acessa a mesma String no pool.

Espero ter ajudado.

Abraços.

Err… não. Nesse caso você vai ter 2 objetos diferentes que contém “testando…”. Quando você faz o sysout, você cria um objeto, imprime-o e libera a referência. Na segunda linha, você tenta criar um novo objeto mas como o mesmo já está criado no pool de Strings, ele referencia esse objeto. Agora na terceira linha, não importando se há ou não objetos criados, ele vai criar um segundo objeto com o conteúdo “testando…” com uma referência totalmente diferente. No final, você acaba tendo 2 referências diferentes e 2 objetos também diferentes, apesar do conteúdo idêntico.

Até!

lgi2020

maquiavelbona:
lgi2020:
É como o amigo acima falou:

Toda String em Java, independente se for criada com new, ou numa atribuição, ou numa concatenação, é armazenada em um local espcial: o pool de Strings.

Dessa forma, temos o seguinte:

System.out.println("testando..."); //aqui se cria a String no pool de Strings. Não há objetos referenciando a String. String teste1 = "testando..."; //como esta String já existe, faz referência à String que já está no pool. 1 Objeto referenciando essa String. String teste2 = new String("testando..."); //2 Objetos referenciando a mesma String.

Se as Strings pudessem ser alteradas, você teria referências inconsistentes, já que vários Objetos sem qualquer ligação acessa a mesma String no pool.

Espero ter ajudado.

Abraços.

Err… não. Nesse caso você vai ter 2 objetos diferentes que contém “testando…”. Quando você faz o sysout, você cria um objeto, imprime-o e libera a referência. Na segunda linha, você tenta criar um novo objeto mas como o mesmo já está criado no pool de Strings, ele referencia esse objeto. Agora na terceira linha, não importando se há ou não objetos criados, ele vai criar um segundo objeto com o conteúdo “testando…” com uma referência totalmente diferente. No final, você acaba tendo 2 referências diferentes e 2 objetos também diferentes, apesar do conteúdo idêntico.

Até!

Amigo,

A String “testando…” será usada em todos os N objetos String que existirem e também nos sysout, concatenações…
Isso é o que eu entendo por funcionamento das Strings em Java.
Podemos não ter nenhum objeto referenciando a String.
Mas enquanto ela não for varrida do pool, qualquer novo objeto a utilizará.

De qualquer forma, embora ache que estou certo, não sou o dono absoluto da verdade e do conhecimento.
Aceito críticas e correções!

Abraços a todos.

blackout

Mas cara, nesse caso alguém tem que explicar.

Porque se quando a pessoa deixa explicito um new na criação do objeto, tipo String teste = new String(“testetando…”);, o pool de Strings adiciona esse valor no pool independente de ter ou não. Realmente teriam dois objetos no exemplo que você deu.

Agora a pergunta a ser respondida é:
Quando vc dá um new numa criação de objeto String, o pool de Strings adiciona esse valor ao pool independente dos valores lá contidos?

maquiavelbona

lgi2020:
[…
Amigo,

A String “testando…” será usada em todos os N objetos String que existirem e também nos sysout, concatenações…
Isso é o que eu entendo por funcionamento das Strings em Java.
Podemos não ter nenhum objeto referenciando a String.
Mas enquanto ela não for varrida do pool, qualquer novo objeto a utilizará.

De qualquer forma, embora ache que estou certo, não sou o dono absoluto da verdade e do conhecimento.
Aceito críticas e correções!

Abraços a todos.


Então, humanamente poderia se pensar assim, mas a JVM não trabalha dessa maneira. Em qualquer classe de objeto, uma criação explícita ( new Blablabla() ) gera sempre um novo objeto. A diferença é que em String e Integer ( não lembro se em outros Wrappers funciona de maneira semelhante ), há um pool de reaproveitamento, pois esses objetos consomem muita memória e para facilitar esse mecanismo, existe a criação implicita ( sem o uso do new ). Independentemente do conteúdo ser idêntico, os objetos não necessariamente serão. No caso:

String teste1 = new String("teste"); String teste2 = "teste";
Haverá somente 1 objeto “teste” no pool, pois na primeira linha, esse objeto é criado de qualquer maneira por causa do new, na segunda linha, antes de tentar criar, ele irá varrer o pool e procurar por um objeto de conteúdo idêntico e como vai achar, ele somente vai referenciar o mesmo objeto.

Num segundo caso:

String teste3 = "agora"; String teste4 = new String("agora");
Haverão 2 objetos com o mesmo conteúdo. Primeiro ele varre o pool, não encontra um objeto semelhante e cria-o. Depois, independente do pool, um novo objeto será criado com o conteúdo idêntico.

Agora, mesmo que não haja nenhuma referência apontando esses objetos, eles não serão liquidados logo, devendo esperar pela passagem do garbage collector ( na verdade, 2 passagens, mas isso é motivo para outro tópico ), podendo assim serem reaproveitados.

Até!

maquiavelbona

blackout:

Agora a pergunta a ser respondida é:
Quando vc dá um new numa criação de objeto String, o pool de Strings adiciona esse valor ao pool independente dos valores lá contidos?

Sim. Apesar da imutabilidade, algumas vezes você pode requerer que um novo objeto seja criado a força e como existe um pool para ele, pode haver mais de um objeto idêntico no pool.

Até!

L

blackout:
Mas cara, nesse caso alguém tem que explicar.

Porque se quando a pessoa deixa explicito um new na criação do objeto, tipo String teste = new String(“testetando…”);, o pool de Strings adiciona esse valor no pool independente de ter ou não. Realmente teriam dois objetos no exemplo que você deu.

Agora a pergunta a ser respondida é:
Quando vc dá um new numa criação de objeto String, o pool de Strings adiciona esse valor ao pool independente dos valores lá contidos?

Sim!

ao meu ver, isso é desta forma, pq vc está “mandando” a JVM criar uma nova instância, então ela tem que fazer isso. O pool só funciona
com atribuições diretas…q dai sim…a JVM entende que vc passou o controle pra ela.

Não consigo ver um caso em que seja necessário, ou recomendável usar new pra String, mas tvz até tenha. Pq senão o construtor poderia
ser privado…eu acho… :smiley:

blackout

Ok, se o lgi2020 concordar, acho que podemos encerrar a questão!!!

Criado 27 de fevereiro de 2008
Ultima resposta 27 de fev. de 2008
Respostas 16
Participantes 8