Olá Pessoal, tudo bom?
Chega de falar sobre certificação :-D, vamos hoje falar sobre a classe String e as formas de realizar a sua instanciação.
java.lang.String – Instanciação
De acordo com a API da classe String, existem duas formas de iniciar uma classe String:
1 2 |
String x = "abc"; String y = new String("abc"); |
O mais comum é que o desenvolvedor menos experiente na linguagem ache que uma instanciação com aspas duplas é igual a uma instanciação com o construtor da classe String. O que não é verdadeiro. Mas qual é a diferença entre utilizar aspas duplas e utilizar o construtor new?
Instanciando com Aspas Duplas
Vamos observar o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package br.com.mauda.string; import junit.framework.Assert; import org.junit.Test; public class TesteString1 { @Test public void teste(){ String a = "abcd"; String b = "abcd"; Assert.assertTrue(a == b); Assert.assertTrue(a.equals(b)); } } |
Esse teste foi construído para rodar na ferramenta JUnit. Caso não conheça a ferramenta há um tutorial aqui.
A linha 15 será verdadeira, em primeiro lugar pois é uma comparação de endereços de memória, o que nos leva a pergunta, mas como é que duas Strings diferentes podem estar no mesmo endereço de memória?
De acordo com a API da classe String temos:
Strings are constant; their values cannot be changed after they are created. Because String objects are immutable they can be shared. For example:
1 String str = "abc";is equivalent to:
12 char data[] = {'a', 'b', 'c'};String str = new String(data);
Traduzindo 🙂 A classe String é constante, ou seja, os valores não podem ser modificados após a sua criação, o que permite que elas possam ser compartilhadas entre vários “ponteiros” (mais detalhes sobre ponteiros, veja aqui). Assim uma String instanciada com aspas duplas é igual a instanciação de uma String via construtor de um vetor de caracteres.
Assim a Figura 01 abaixo representa o que ocorre na linha 15:
Já a linha 16 é correta, pois é uma comparação com o método equals, o qual é sobrescrito na classe String e compara o valor dos caracteres internos, logo essa linha será verdadeira também.
Instanciando via Construtor
Vamos observar o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package br.com.mauda.string; import junit.framework.Assert; import org.junit.Test; public class TesteString2 { @Test public void teste(){ String c = new String("abcd"); String d = new String("abcd"); Assert.assertTrue(c == d); Assert.assertTrue(c.equals(d)); } } |
E agora, o que você acha, a linha 15 será verdadeira ou falsa? e a linha 16?
Vamos começar pela mais fácil a linha 16 será verdadeira, pois continua utilizando o mesmo método equals do teste anterior, logo a comparação realizada é com o conteúdo da String o que torna a linha verdadeira.
Já a linha 15 será falsa! Sim, falsa! Mas as Strings não são imutáveis e compartilhadas? Sim! Mas então por que é falsa a execução desta linha. Para isso vamos olhar a Figura 02 abaixo:
Repare que ao criar as novas instâncias via construtor elas são armazenadas em endereços de memória distintos, mas esses endereços apontam para a mesma String imutável. Lembre-se para a criar a String com o construtor, o que você precisou criar? Uma String com aspas duplas!!! Logo você está fazendo um encapsulamento de Strings, pois você criou uma String e armazenou esta dentro de outra String!
Existe uma forma de resolver esse problema, utilizando o método da classe String chamado intern(), link da API, assim o exemplo abaixo irá passar corretamente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package br.com.mauda.string; import junit.framework.Assert; import org.junit.Test; public class TesteString3 { @Test public void teste(){ String c = new String("abcd").intern(); String d = new String("abcd").intern(); Assert.assertTrue(c == d); Assert.assertTrue(c.equals(d)); } } |
A Figura 03, representa a Heap do java após a execução deste teste:
A pergunta que deve surgir é como não foram criadas as outras instâncias da classe String, conforme a Figura 02? É porque no caso do método intern o compilador Java, durante a geração dos bytecodes, remove o new String e deixa apenas a String com aspas duplas “abcd”. Assim não haverão mais 2 instâncias ocupando memória do Java.
finnaly{
Para finalizar, não utilize o construtor da classe String apenas irá criar um objeto a mais, pois a String que você deseja já existe em memória.
Duvidas ou sugestões? Achou outros livros que possam ser colocados aqui? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Leave a Reply