Se não me falha a memória, parece que já ouvi dizer que, por razões que não me lembro, não é uma boa utilizarmos new String(…) para criarmos uma instância de String.
Isso é verdade? Por quê? Isso vale para todos os construtores de String?
Valeu pessoal!
Parece que ele não usa o cache de Strings quando você usa new…algo assim…mas não tenho total certeza…hehehe
No que já foi dito nesse fórum, quando você usa a atribuição String var1 = “texto”, ele procura num pool se strings, se tiver utiliza aquele string, senão cria uma nova no mesmo pool. Assim quando ele for fazer String var2 = “texto” , ele não cria uma string nova e sim referencia a mesma. Quando utilizas String var3 = new String(“texto”), cria-se obrigatoriamente uma nova string.
Não sei se realmente isso procede, mas lembrar não é afirmar.
Até!
Realmente como disse o maquiavelbona há um mecanismo de otimização do uso de memória na JVM que consiste em um Pool de Strings, quando você cria uma String sem usar o new, primeiro é verificado no Pool de Strings se existe uma String igual à aquela, se sim, não é criada outra, somente referenciada a que já existe, se não, é criada uma nova e adicionada ao Pool.
Ao usar o operador new, obrigatoriamente é criado um novo objeto, para qualquer classe que seja. Então, se você tiver 1000 objetos String com “texto”, se você cria-los usando um literal, haverá apenas 1 objeto na memoria e 1000 referencias para ele, se você usar new String(“texto”) serão criados 1000 objetos e 1000 referencias, uma para cada um.
Outras classes tambem tem algum tipo de otimização, como um cache para valores Integer, se você usar new Integer(1) você criará um novo objeto, se usar Integer.valueOf(1) será usado um que já existe, e ele sempre existe, pois é criado ao carregar a classe Integer, esse cache de Integer funciona de -127 a 128, ou seja, nunca é criado um novo objeto Integer para valores nessa faixa, se você usar Integer.valueOf() claro. Mas essa é uma otimização mais simples que a da String.
[quote=jairelton]Realmente como disse o maquiavelbona há um mecanismo de otimização do uso de memória na JVM que consiste em um Pool de Strings, quando você cria uma String sem usar o new, primeiro é verificado no Pool de Strings se existe uma String igual à aquela, se sim, não é criada outra, somente referenciada a que já existe, se não, é criada uma nova e adicionada ao Pool.
Ao usar o operador new, obrigatoriamente é criado um novo objeto, para qualquer classe que seja. Então, se você tiver 1000 objetos String com “texto”, se você cria-los usando um literal, haverá apenas 1 objeto na memoria e 1000 referencias para ele, se você usar new String(“texto”) serão criados 1000 objetos e 1000 referencias, uma para cada um.
Outras classes tambem tem algum tipo de otimização, como um cache para valores Integer, se você usar new Integer(1) você criará um novo objeto, se usar Integer.valueOf(1) será usado um que já existe, e ele sempre existe, pois é criado ao carregar a classe Integer, esse cache de Integer funciona de -127 a 128, ou seja, nunca é criado um novo objeto Integer para valores nessa faixa, se você usar Integer.valueOf() claro. Mas essa é uma otimização mais simples que a da String.[/quote]
Uma vez eu usei Integer.valueOf e quando um valor nunca tinha sido adicionado usando new o valueOf não tava retornando. Achei muito estranho, mas não fiquei investigando muito pq tava atrasadão com o projeto! hehe Joguei um new mesmo.
Eu já conhecia esse recurso do pool de Strings, mas de fato não tinha atentado para o fato de que um new String(…) “quebraria” esta otimização.
De qualquer forma, fiz essa pergunta porque estava olhando o código fonte da classe Integer, mais precisamente o método toString(int, int), e reparei que ele retorna um String instanciado a partir de um determinado construtor, e achei estranho o uso de algo que eu sabia que não era legal (só não sabia o porquê) dentro de uma classe da API do JSE.
Se o problema em usar construtores da classe String for apenas a quebra da otimização do pool de strings, então realmente não há inconveniente algum - eu presumo - em a classe Integer utilizar o tal construtor, pois acho que cada escopo local deve ter o seu pool próprio de strings (ou algo assim).
Obrigado a todos, e corrijam-me se disse alguma bobagem.
:thumbup:
Até onde eu sei tem a ver com o pool de Strings, pois quando você da um new ele cria sem verificar a existência no pool ,ele OBRIGATORIAMENTE cria uma nova instância e não sei como fica o tratamento para avaliar se existe ou não no pool.
E se não me engano ainda existem duas questões.
Quando você faz String b = new String("teste");
Você acaba criando dois objetos.A string “teste” e o objeto string que contém o mesmo conteúdo do objeto teste.
Essa afirmação não tenho muita certeza,mas eu acho que ela procede.
O único construtor que não acho legal de String é o “new String(String)”, pois faz uma cópia de um objeto imutável (você se lembra direitinho que String é um classe cujas instâncias são imutáveis), e mesmo assim com ressalvas - existe um caso em que ele é útil.
Digamos que você tenha uma string imensa, de 1MB, e você só queira dela uma substring de 10K. E depois de pegar essa substring, você queira descartar essa string. (É um caso raro, mas aparece às vezes).
Se você olhar o fonte do método substring, vai ver que ele simplesmente pega o char[] da string original, e cria um novo objeto String que aponta para esse mesmo char[], só que com offset e length diferentes.
Ou seja, a string original de 1MB contém um char[] de 1MB, e a substring aponta também para esse mesmo char[] de 1MB.
Digamos que a string original não seja mais usada. Mesmo assim, o char[] de 1MB vai continuar “vivo” porque é usada pela substring criada depois.
Se você usar String stringPequena = new String (stringEnorme.substring (0, 10000)) , você irá criar um novo char[] de 10000 caracteres, copiar os 10000 caracteres da string original para a nova string, e então a string original estará livre para ser descartada, se você não precisar mais dela.
Entretanto, se você tiver uma string XML gigante e quebrá-la em tags (ou seja, muitas strings pequenas), provavelmente é melhor usar o comportamento padrão - por velocidade (já que não é feita nenhuma cópia desnecessária) e porque não há economia nesse caso.
Na realidade ele não manteria a referencia da String de 1MB porque o construtor String(char[], int, int) faz uma copia do array antes de armazenar, veja:
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
char[] v = new char[count];
System.arraycopy(value, offset, v, 0, count);
this.offset = 0;
this.count = count;
this.value = v;
}
Então haveriam 2 char[] na memória, 1 com 1MB e outro com 10K, o de 1MB iria para o limbo logo que o objeto String fosse coletado.
Acho que vou tirar o “[resolvido]” deste tópico… Tá ficando interessante!!! :lol:
Uma coisa boa do JDK é que os fontes estão disponíveis para todo mundo ver. Se você ler cuidadosamente o fonte de java.lang.String vai descobrir um monte de coisas interessantes