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.