Strings são objetos em Java, então por que não usamos 'new' para criá-los?


104

Normalmente criamos objetos usando a newpalavra - chave, como:

Object obj = new Object();

Strings são objetos, mas não usamos newpara criá-los:

String str = "Hello World";

Por que é isso? Posso fazer uma corda com new?


Você também deve dar uma olhada nesta questão stackoverflow.com/questions/456575/java-wrapper-equality-test
alterado em

1
Porque literais de string já são objetos.
Marquês de Lorne

1
Observe que new String(...)foi usado para contornar um detalhe de implementação ao criar substring de strings grandes. Isso foi corrigido no Java 7 e não é mais necessário.
Thorbjørn Ravn Andersen

Eu sou o centésimo apreciador deste post. :)
Mukit09

Respostas:


130

Além do que já foi dito, literais String [ou seja, Strings like "abcd"but not like new String("abcd")] em Java são internados - isso significa que toda vez que você se refere a "abcd", você obtém uma referência para uma única Stringinstância, em vez de uma nova cada vez. Então você terá:

String a = "abcd";
String b = "abcd";

a == b; //True

mas se você tivesse

String a = new String("abcd");
String b = new String("abcd");

então é possível ter

a == b; // False

(e caso alguém precise ser lembrado, use sempre .equals()para comparar Strings; ==testes de igualdade física).

Internar literais String é bom porque geralmente são usados ​​mais de uma vez. Por exemplo, considere o código (inventado):

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

Se não tivéssemos internação de Strings, a "Próxima iteração" precisaria ser instanciada 10 vezes, enquanto agora será instanciada apenas uma vez.


1
Ao usar String a = new String ("abcd"), isso significa que duas strings com conteúdo semelhante estão presentes na memória.
alterado em

1
Certo - o compilador não irá necessariamente verificar se tal String já foi internada (embora você certamente possa escrever uma que o tenha).
danben

sim, essa otimização é possível porque as strings são imutáveis ​​e, portanto, podem ser compartilhadas sem problemas. o tratamento compartilhado de "asdf" é uma implementação do padrão de design 'Flyweight'.
manuel aldana

Ninguém disse que não é possível, apenas que não é garantido. Esse foi o seu downvote?
danben

O que você quer dizer com "== testa a igualdade do objeto"? Isso não parece verdade para mim, mas talvez você quisesse dizer algo diferente do que isso parece significar.
Dawood ibn Kareem

32

Strings são objetos "especiais" em Java. Os designers Java sabiamente decidiram que Strings são usados ​​com tanta frequência que eles precisavam de sua própria sintaxe, bem como de uma estratégia de cache. Quando você declara uma string dizendo:

String myString = "something";

myString é uma referência ao objeto String com um valor de "something". Se você declarar posteriormente:

String myOtherString = "something";

Java é inteligente o suficiente para descobrir que myString e myOtherString são iguais e irá armazená-los em uma tabela String global como o mesmo objeto. Depende do fato de que você não pode modificar Strings para fazer isso. Isso reduz a quantidade de memória necessária e pode tornar as comparações mais rápidas.

Se, em vez disso, você escrever

String myOtherString = new String("something");

Java criará um novo objeto para você, distinto do objeto myString.


Ei ... não requer "sabedoria infinita" para reconhecer a necessidade de algum tipo de suporte sintático para literais de string. Quase todos os outros projetos de linguagem de programação sérios suportam algum tipo de literal de string.
Stephen C

12
A hipérbole foi reduzida a atordoar, capitão :)
Jamie McCrindle

16
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

Espero que isso esclareça algumas dúvidas. :)


String d = nova String ("def"); // 1 Objeto + "def" é adicionado ao Pool -> aqui "def" seria adicionado ao pool apenas se ainda não estivesse lá
southerton

@southerton Sem sentido. Já está na piscina. Ele foi colocado lá pelo compilador.
Marquês de Lorne

@EJP porque (e == d) é falso aqui? ambos estão se referindo ao mesmo objeto "def" na piscina, certo?
Raja

String c = nova String ("abc"); // 1 Objeto ... esta afirmação está correta? Se "abc" já foi referenciado a partir do pool de constantes, então qual é o uso do método inter?
Prashanth Debbadwar

6

É um atalho. Não era originalmente assim, mas o Java mudou.

Este FAQ fala sobre isso brevemente. O guia de especificações Java também fala sobre isso. Mas não consigo encontrar online.


2
Link quebrado, e não tenho conhecimento de nenhuma outra evidência de que tenha sido alterado.
Marquês de Lorne

1
@EJP Ainda está na máquina de retorno, se isso for útil.
Arjan de

6

String está sujeita a algumas otimizações (por falta de uma frase melhor). Observe que String também tem sobrecarga de operador (para o operador +) - ao contrário de outros objetos. Portanto, é um caso muito especial.


1
O + é na verdade um operador que é traduzido em uma chamada StringBuilder.append (..).
whiskyierra

5

Normalmente usamos literais String para evitar a criação de objetos desnecessários. Se usarmos o novo operador para criar o objeto String, ele criará um novo objeto todas as vezes.

Exemplo:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

Para o código acima na memória:

insira a descrição da imagem aqui


2

Em Java, Strings são um caso especial, com muitas regras que se aplicam apenas a Strings. As aspas duplas fazem com que o compilador crie um objeto String. Como os objetos String são imutáveis, isso permite que o compilador internalize várias strings e construa um pool de strings maior. Duas constantes String idênticas sempre terão a mesma referência de objeto. Se você não quiser que seja esse o caso, você pode usar new String (""), e isso criará um objeto String em tempo de execução. O método intern () costumava ser comum, para fazer com que as strings criadas dinamicamente fossem verificadas na tabela de pesquisa de strings. Depois que uma string for internada, a referência do objeto apontará para a instância canônica de String.

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

Quando o carregador de classe carrega uma classe, todas as constantes String são adicionadas ao pool de String.


"As aspas duplas fazem com que o compilador crie um objeto String." comentário subvalorizado
csguy

0

Açúcar sintático. o

String s = new String("ABC");

a sintaxe ainda está disponível.


1
Isso não está certo. s = new String ("ABC") não fornecerá os mesmos resultados que s = "ABC". Veja o comentário de danben.
Steve B.

2
Além disso, um tanto ironicamente, ele primeiro criará uma instância de String representando "ABC" embutido - e então passará isso como um argumento para a chamada do construtor que criará um retorno de uma String de valor idêntico.
Andrzej Doyle

1
O caso de uso válido para esse construtor é String small = new String(huge.substring(int, int));, que permite reciclar o grande subjacente char[]da hugeString original .
Pascal Thivent

1
@PascalThivent sim, mas não mais com Java 8. Ele não compartilha mais arrays (em preparação para outras otimizações como desduplicação automática de string com G1 ou compressão de string futura).
eckes de

@AndrzejDoyle Incorreto. O compilador cria o objeto para o literal.
Marquês de Lorne

0

Você ainda pode usar new String("string"), mas seria mais difícil criar novas strings sem literais de string ... você teria que usar matrizes de caracteres ou bytes :-) Literais de string têm uma propriedade adicional: todos os mesmos literais de string de qualquer ponto de classe para a mesma string instância (eles estão internados).


0

Quase não há necessidade de uma nova string, pois o literal (os caracteres entre aspas) já é um objeto String criado quando a classe host é carregada. É perfeitamente legal invocar métodos em um literal e don, a principal diferença é a conveniência fornecida pelos literais. Seria uma grande dor e desperdício de tempo se tivéssemos que criar um array de chars e preenchê-lo com char e eles fazendo uma nova String (char array).


0

Sinta-se à vontade para criar uma nova String com

String s = new String("I'm a new String");

A notação usual s = "new String";é mais ou menos um atalho conveniente - que deve ser usado por motivos de desempenho, exceto para aqueles casos muito raros, onde você realmente precisa de Strings que se qualifiquem para a equação

(string1.equals(string2)) && !(string1 == string2)

EDITAR

Em resposta ao comentário: isto não pretendia ser um conselho, mas apenas uma resposta direta à tese dos questionadores, de que não usamos a palavra-chave 'nova' para Strings, o que simplesmente não é verdade. Espero que esta edição (incluindo a acima) esclareça isso um pouco. BTW - há algumas respostas boas e muito melhores para a pergunta acima no SO.


4
-1 - Mau conselho. Você NÃO deve "se sentir à vontade" para usar A new String(...)MENOS que seu aplicativo EXIGE que você crie uma String com uma identidade distinta.
Stephen C

1
Eu sei disso. Editou a postagem para esclarecimento.
Andreas Dolk

0

O conjunto literal contém quaisquer Strings que foram criadas sem usar a palavra-chave new.

Há uma diferença: String sem nova referência é armazenada no pool literal de String e String com new diz que eles estão na memória heap.

String com new estão em outro lugar na memória como qualquer outro objeto.


0

Porque String é uma classe imutável em java.

Agora, por que é imutável? Como String é imutável, pode ser compartilhado entre vários threads e não precisamos sincronizar a operação de String externamente. As String também é usado no mecanismo de carregamento de classe. Portanto, se String fosse mutável, java.io.writer poderia ter sido alterado para abc.xyz.mywriter


0
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

Resultado:

Verdade

Criei dois objetos separados, ambos têm um campo (ref) 'Nome'. Portanto, mesmo neste caso, "Jan Peter" é compartilhado, se eu entendo como o java trata ..


0

Bem, o StringPool é implementado usando o Hashmap em java. Se estivermos criando sempre com uma nova palavra-chave, ele não estará pesquisando no String Pool e criando uma nova memória para ela que pode ser necessária mais tarde se tivermos uma operação com uso intensivo de memória em execução e se estivermos criando todas as strings com uma nova palavra-chave que afetaria o desempenho de nosso aplicativo. Portanto, é aconselhável não usar novas palavras-chave para a criação de string, pois só então ele irá para o pool de String que por sua vez é um Hashmap, (memória salva, imagine se tivermos muitas strings criadas com a nova palavra-chave) aqui ele será armazenado e se a string já existe, a referência dela (que normalmente residiria na memória da pilha) seria retornada para a string recém-criada. Portanto, é feito para melhorar o desempenho.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.