public class Ex {
String str1 = new String("musica");
String str2 = "musica";
...
}
Por incrível que pareça, essas duas formas de instanciação de String são completamente diferentes.
A variável str1 tem seu valor armazenado no heap de memória reservado para o objeto que a cria. A segunda como não é criada com o operador new, tem seu valor armazenado em uma região especial da memória de JVM chamada de pool de Strings. E você diz, e daí?
O pool de String foi criada para economizar memória. Como?
String str1 = "musica";
String str2 = "musica";
String str3 = "musica";
String str4 = "musica";
Bytes usados somente para conteúdo: 6 bytes.
Todos estão em posicão diferentes no heap. Contudo, eles apontam para o mesmo valor de memória. Assim, temos economia.
String str1 = new String("musica");
String str2 = new String("musica");
String str3 = new String("musica");
String str4 = new String("musica");
Bytes usados somente para conteúdo: 24 bytes.
Agora, porque ter a opção de gastar memória para aparentemente fazer a mesma coisa? Quando Strings são instânciadas sem new, é necessário procurar o valor recebido no pool, assim, é mais custo por ter comparação.
Agora, vou desmitificar um mito do java, a comparação de Strings. Quem disse que só dá para comparar por equals(String)::boolean?
O método intern()::String da classe String permite comparação por != e ==.
A descrição do método diz que ele retorna a forma canônica da String, como se fosse um tipo primitivo. Contudo, www.paste.la/861 dá a entender que ele cria o conteúdo da String no pool.
James Gosling (criador do Java), afirma em seu livro, A linguagem de programação Java, que comparar por intern()::String é mais eficiente.