Qualquer pessoa, por favor responda a isso. String a = "Java"; String b = "Java"; System.out.println (a == b); true // mas System.out.println ("a == b?" + a == b); // false ...
Energia
eu não entendo quando adicionei algum comentário ("a == b?) => meu resultado se torna FALSO. por quê?
Energia
@Energy O resultado é falseque a ordem das operações determina que o operador + seja o primeiro, concatenando "a == b?" com a para criar uma String "a == b? Java". Em seguida, a expressão é "a==b?Java" == bavaliada como falsa.
Allison B
@AllisonB entendi, muito obrigado!
Energia
Respostas:
187
new String("text");
cria explicitamente uma instância nova e referencialmente distinta de um Stringobjeto; String s = "text";pode reutilizar uma instância do pool constante de cadeias, se houver uma disponível.
Você raramente gostaria de usar o new String(anotherString)construtor. Na API:
String(String original): Inicializa um objeto recém-criadoString para que ele represente a mesma sequência de caracteres que o argumento; em outras palavras, a sequência recém-criada é uma cópia da sequência de argumentos. A menos que uma cópia explícita do original seja necessária, o uso desse construtor é desnecessário, pois as strings são imutáveis.
==em dois tipos de referência é uma comparação de identidade de referência. Dois objetos que equalsnão são necessariamente ==. Geralmente, é errado usar ==em tipos de referência; a maior parte do tempo equalsprecisa ser usada.
No entanto, se por qualquer motivo você precisar criar duas, equalsmas não uma ==sequência, poderá usar o new String(anotherString)construtor. É preciso dizer novamente, porém, que isso é muito peculiar e raramente é a intenção.
Se eu escrever: String s = new String ("abc"); E agora eu escrevo: String s = "abc"; Will String s = "abc"; criar um novo literal String no pool String?
Kaveesh Kanwal
Por que ninguém responde à pergunta anterior?
zeds
2
@KaveeshKanwal Não, o literal não será duplicado. Como você pode ver, existem 2 "abc"s. Apenas um deles irá para o pool String e o outro fará referência a ele. Depois, há o sque será o novo objeto apropriado.
Kayaman
1
@Kaveesh Kanwal - String s = new String ("abc") criará apenas um novo objeto String com o valor "abc". E a segunda instrução verificará se existe algum literal de string "abc" já presente no Pool de String ou não. Se já estiver presente, a referência ao existente será retornada e, se não estiver, um novo literal ("abc") será criado no pool de String. Espero que resolva sua consulta !!
User968813
Não há 'maio' sobre isso. O compilador deve agrupar literais de seqüência de caracteres. JLS 3.10.5 .
Marquês de Lorne
119
Literais de seqüência de caracteres irão para o Pool de Constantes de String .
O instantâneo abaixo pode ajudá-lo a entendê-lo visualmente para lembrá-lo por mais tempo.
Criação de objeto linha por linha:
String str1 =newString("java5");
Usando a string literal "java5" no construtor, um novo valor da string é armazenado no pool constante da string. Usando o novo operador, um novo objeto de sequência é criado no heap com "java5" como valor.
String str2 ="java5"
A referência "str2" está apontada para o valor já armazenado no pool constante de strings
String str3 =newString(str2);
Um novo objeto de string é criado no heap com o mesmo valor da referência por "str2"
String str4 ="java5";
A referência "str4" está apontada para o valor já armazenado no pool constante de strings
Boa resposta .. mas quero saber que agora estou pensando em mudar o valor de str1 = "java6", então ele mudará o valor de str4?
CoronaPintu
2
Sim, eu tive verificar que não irá alterar o valor de str4
CoronaPintu
@Braj Você pode fornecer documentação da afirmação do seu respondente?
Basil Bourque
@Braj: Os cabeçalhos do 'Heap' e 'pool' na tabela devem ser reversos?
Rahul Kurup
Incorreto. O pool constante é criado no tempo de compilação, não no tempo de execução. Não use formatação de citação para texto que não está entre aspas.
o outro cria uma sequência no pool constante ( "text") e outra no espaço de pilha normal ( s). Ambas as strings terão o mesmo valor, o de "text".
String s =newString("text");
s é então perdido (elegível para o GC) se não for usado posteriormente.
Literais de string, por outro lado, são reutilizados. Se você usar "text"em vários locais da sua classe, será de fato uma e apenas uma String (ou seja, várias referências à mesma string no pool).
Além disso, um literal de string sempre se refere à mesma instância da classe String. Isso ocorre porque literais de strings - ou, de maneira mais geral, strings que são os valores de expressões constantes (§15.28) - são "internados" para compartilhar instâncias exclusivas, usando o método String.intern.
Exemplo 3.10.5-1. Literais de cordas
O programa que consiste na unidade de compilação (§7.3):
Um literal de string é uma referência a uma instância da classe String e é derivado de uma estrutura CONSTANT_String_info (§4.4.3) na representação binária de uma classe ou interface. A estrutura CONSTANT_String_info fornece a sequência de pontos de código Unicode que constituem a cadeia literal.
A linguagem de programação Java requer que literais de string idênticos (ou seja, literais que contenham a mesma sequência de pontos de código) se refiram à mesma instância da classe String (JLS §3.10.5). Além disso, se o método String.intern for chamado em qualquer string, o resultado será uma referência à mesma instância de classe que seria retornada se essa string aparecesse como um literal. Portanto, a seguinte expressão deve ter o valor true:
("a"+"b"+"c").intern()=="abc"
Para derivar um literal de cadeia, a Java Virtual Machine examina a sequência de pontos de código fornecidos pela estrutura CONSTANT_String_info.
Se o método String.intern já foi chamado em uma instância da classe String que contém uma sequência de pontos de código Unicode idênticos àqueles fornecidos pela estrutura CONSTANT_String_info, o resultado da derivação literal da string é uma referência à mesma instância da classe String.
Caso contrário, uma nova instância da classe String será criada contendo a sequência de pontos de código Unicode fornecidos pela estrutura CONSTANT_String_info; uma referência a essa instância de classe é o resultado da derivação literal de cadeia de caracteres. Por fim, o método interno da nova instância String é chamado.
Bytecode
Também é instrutivo examinar a implementação de bytecode no OpenJDK 7.
Se decompilarmos:
publicclassStringPool{publicstaticvoid main(String[] args){String a ="abc";String b ="abc";String c =newString("abc");System.out.println(a);System.out.println(b);System.out.println(a == c);}}
str1não está envolvido no valor de str2ou str3ou str4de qualquer forma.
Marquês de Lorne
1
Pense em "bla"ser uma fábrica mágica como Strings.createString("bla")(pseudo). A fábrica possui um conjunto de todas as strings criadas dessa maneira.
Se for invocado, ele verifica se já existe uma sequência no pool com esse valor. Se verdadeiro, ele retorna esse objeto de string, portanto, as strings obtidas dessa maneira são realmente o mesmo objeto.
Caso contrário, ele cria um novo objeto de cadeia internamente, o salva no pool e o retorna. Portanto, quando o mesmo valor da string é consultado na próxima vez, ele retorna a mesma instância.
A criação manual new String("")substitui esse comportamento ignorando o pool literal de cadeias. Portanto, a igualdade deve sempre ser verificada usando o equals()que compara a sequência de caracteres em vez da igualdade de referência do objeto.
A 'fábrica mágica' a que você se refere é nada mais ou menos que o compilador Java. É um erro escrever esse processo como se tivesse ocorrido em tempo de execução.
Marquês de Lorne
1
Uma maneira simples de entender a diferença está abaixo:
String s ="abc";String s1="abc";String s2=newString("abc");if(s==s1){System.out.println("s==s1 is true");}else{System.out.println("s==s1 is false");}if(s==s2){System.out.println("s==s2 is true");}else{System.out.println("s==s2 is false");}
saída é
s==s1 is true
s==s2 is false
Assim, novo String () sempre criará uma nova instância.
Qualquer literal de String é criado dentro do pool literal de strings e o pool não permite duplicatas. Portanto, se dois ou mais objetos de string forem inicializados com o mesmo valor literal, todos os objetos apontarão para o mesmo literal.
String obj1 ="abc";String obj2 ="abc";
"obj1" e "obj2" apontarão para a mesma string literal e o pool literal de strings terá apenas um literal "abc".
Quando criamos um objeto de classe String usando a nova palavra-chave, a string criada é armazenada na memória heap. Qualquer literal de cadeia passada como parâmetro para o construtor da classe String, no entanto, é armazenada no conjunto de cadeias. Se criarmos vários objetos usando o mesmo valor com o novo operador, um novo objeto será criado na pilha a cada vez, por causa desse novo operador deve ser evitado.
"obj1" e "obj2" apontarão para dois objetos diferentes no heap e o pool literal de cadeias terá apenas um literal "abc".
Também algo que vale a pena observar com relação ao comportamento das strings é que qualquer nova atribuição ou concatenação feita na string cria um novo objeto na memória.
Agora, no caso acima:
Linha 1: literal "abc" é armazenado no pool de cadeias.
Linha 2: o literal "abcdef" é armazenado no pool de strings.
Linha 3: Um novo literal "xyz" é armazenado no pool de strings e "str1" começa a apontar para esse literal.
Linha 4: Como o valor é gerado anexando a outra variável, o resultado é armazenado na memória heap e o literal que está sendo anexado "ghi" será verificado quanto à sua existência no pool de strings e será criado, uma vez que não existe no o caso acima.
Embora pareça o mesmo do ponto de vista dos programadores, ele tem um grande impacto no desempenho. Você deseja usar o primeiro formulário quase sempre.
Ele irá verificar se o pool constante de String já contém String "hello"? Se presente, ele não adicionará uma entrada no pool constante de String. Se não estiver presente, ele adicionará uma entrada no pool constante de String.
Um objeto será criado em uma área de memória de heap e strpontos de referência para o objeto criado no local da memória de heap.
se você deseja fazer strreferência ao objeto de ponto que contém no pool constante de String, é necessário chamar explicitamentestr.intern();
String str ="world";
Ele irá verificar se o pool constante de String já contém String "hello"? Se presente, ele não adicionará uma entrada no pool constante de String. Se não estiver presente, ele adicionará uma entrada no pool constante de String.
Nos dois casos acima, a strreferência aponta para String "world"presente no pool Constant.
'It' sendo o compilador Java. A literal da cadeia de caracteres cria uma entrada exclusiva no pool constante, no momento da compilação. É um erro deacribe este processo como se isso acontece em tempo de execução ..
Marquês de Lorne
Você pode explicar claramente o que está errado neste post?
Jayesh
O que há de errado neste post é que a string literal é agrupada em tempo de execução, como eu já disse. Não ao executar o código, como em sua resposta.
Marquês de Lorne
@EJP Agradeço sua resposta. Você pode apontar a linha exata que está errada na resposta. Vejo que todas as respostas acima são iguais às que escrevi. Por favor, ajude, quero corrigir meu entendimento. Obrigado.
Jayesh
Você escreveu sobre todo o processo como se tudo acontecesse quando a linha de código fosse executada, o que, como já lhe disse várias vezes, não é o caso. Você não pode reduzir tudo isso a uma única 'linha exata' que está errada em sua resposta.
Marquês de Lorne
0
Quando você armazena uma String como
String string1 ="Hello";
diretamente, a JVM cria um objeto String com o preço especificado durante um bloco de memória separado chamado pool constante de String.
E sempre que temos a tendência de tentar produzir outra String como
String string2 ="Hello";
A JVM verifica se existe algum objeto String com preço constante no conjunto de constantes String, se houver, em vez de criar um novo objeto, a JVM atribui a referência do objeto existente à nova variável.
E quando armazenamos String como
String string =newString("Hello");
usando a nova palavra-chave, um novo objeto com o preço especificado é criado, independentemente do conteúdo do pool constante de String.
false
que a ordem das operações determina que o operador + seja o primeiro, concatenando "a == b?" com a para criar uma String "a == b? Java". Em seguida, a expressão é"a==b?Java" == b
avaliada como falsa.Respostas:
new String("text");
cria explicitamente uma instância nova e referencialmente distinta de umString
objeto;String s = "text";
pode reutilizar uma instância do pool constante de cadeias, se houver uma disponível.Você raramente gostaria de usar o
new String(anotherString)
construtor. Na API:Perguntas relacionadas
O que significa distinção referencial
Examine o seguinte trecho:
==
em dois tipos de referência é uma comparação de identidade de referência. Dois objetos queequals
não são necessariamente==
. Geralmente, é errado usar==
em tipos de referência; a maior parte do tempoequals
precisa ser usada.No entanto, se por qualquer motivo você precisar criar duas,
equals
mas não uma==
sequência, poderá usar onew String(anotherString)
construtor. É preciso dizer novamente, porém, que isso é muito peculiar e raramente é a intenção.Referências
class Object
-boolean Object(equals)
Assuntos relacionados
fonte
"abc"
s. Apenas um deles irá para o pool String e o outro fará referência a ele. Depois, há os
que será o novo objeto apropriado.Literais de seqüência de caracteres irão para o Pool de Constantes de String .
O instantâneo abaixo pode ajudá-lo a entendê-lo visualmente para lembrá-lo por mais tempo.
Criação de objeto linha por linha:
Usando a string literal "java5" no construtor, um novo valor da string é armazenado no pool constante da string. Usando o novo operador, um novo objeto de sequência é criado no heap com "java5" como valor.
A referência "str2" está apontada para o valor já armazenado no pool constante de strings
Um novo objeto de string é criado no heap com o mesmo valor da referência por "str2"
A referência "str4" está apontada para o valor já armazenado no pool constante de strings
Total de objetos: Pilha - 2, Piscina - 1
Leitura adicional na comunidade Oracle
fonte
Um cria uma string no pool constante de strings
o outro cria uma sequência no pool constante (
"text"
) e outra no espaço de pilha normal (s
). Ambas as strings terão o mesmo valor, o de "text".s
é então perdido (elegível para o GC) se não for usado posteriormente.Literais de string, por outro lado, são reutilizados. Se você usar
"text"
em vários locais da sua classe, será de fato uma e apenas uma String (ou seja, várias referências à mesma string no pool).fonte
JLS
O conceito é chamado de "interning" pelo JLS.
Passagem relevante da JLS 7 3.10.5 :
JVMS
O JVMS 7 5.1 diz :
Bytecode
Também é instrutivo examinar a implementação de bytecode no OpenJDK 7.
Se decompilarmos:
temos na piscina constante:
e
main
:Observe como:
0
e3
: a mesmaldc #2
constante é carregada (os literais)12
: uma nova instância de string é criada (com#2
como argumento)35
:a
ec
são comparados como objetos regulares comif_acmpne
A representação de strings constantes é bastante mágica no bytecode:
new String
)e a citação da JVMS acima parece dizer que sempre que o Utf8 apontado é o mesmo, instâncias idênticas são carregadas
ldc
.Eu fiz testes semelhantes para campos e:
static final String s = "abc"
aponta para a tabela constante por meio do atributo ConstantValueldc
Conclusão : existe suporte direto de bytecode para o conjunto de strings e a representação de memória é eficiente.
Bônus: compare isso ao pool Inteiro , que não possui suporte direto ao bytecode (ou seja, sem
CONSTANT_String_info
analógico).fonte
@ Braj: Eu acho que você mencionou o contrário. Por favor corrija-me se eu estiver errado
Criação de objeto linha por linha:
String str1 = new String ("java5")
String str2 = "java5"
String str3 = new String (str2)
String str4 = "java5"
fonte
str1
não está envolvido no valor destr2
oustr3
oustr4
de qualquer forma.Pense em
"bla"
ser uma fábrica mágica comoStrings.createString("bla")
(pseudo). A fábrica possui um conjunto de todas as strings criadas dessa maneira.Se for invocado, ele verifica se já existe uma sequência no pool com esse valor. Se verdadeiro, ele retorna esse objeto de string, portanto, as strings obtidas dessa maneira são realmente o mesmo objeto.
Caso contrário, ele cria um novo objeto de cadeia internamente, o salva no pool e o retorna. Portanto, quando o mesmo valor da string é consultado na próxima vez, ele retorna a mesma instância.
A criação manual
new String("")
substitui esse comportamento ignorando o pool literal de cadeias. Portanto, a igualdade deve sempre ser verificada usando oequals()
que compara a sequência de caracteres em vez da igualdade de referência do objeto.fonte
Uma maneira simples de entender a diferença está abaixo:
saída é
Assim, novo String () sempre criará uma nova instância.
fonte
Qualquer literal de String é criado dentro do pool literal de strings e o pool não permite duplicatas. Portanto, se dois ou mais objetos de string forem inicializados com o mesmo valor literal, todos os objetos apontarão para o mesmo literal.
"obj1" e "obj2" apontarão para a mesma string literal e o pool literal de strings terá apenas um literal "abc".
Quando criamos um objeto de classe String usando a nova palavra-chave, a string criada é armazenada na memória heap. Qualquer literal de cadeia passada como parâmetro para o construtor da classe String, no entanto, é armazenada no conjunto de cadeias. Se criarmos vários objetos usando o mesmo valor com o novo operador, um novo objeto será criado na pilha a cada vez, por causa desse novo operador deve ser evitado.
"obj1" e "obj2" apontarão para dois objetos diferentes no heap e o pool literal de cadeias terá apenas um literal "abc".
Também algo que vale a pena observar com relação ao comportamento das strings é que qualquer nova atribuição ou concatenação feita na string cria um novo objeto na memória.
Agora, no caso acima:
Linha 1: literal "abc" é armazenado no pool de cadeias.
Linha 2: o literal "abcdef" é armazenado no pool de strings.
Linha 3: Um novo literal "xyz" é armazenado no pool de strings e "str1" começa a apontar para esse literal.
Linha 4: Como o valor é gerado anexando a outra variável, o resultado é armazenado na memória heap e o literal que está sendo anexado "ghi" será verificado quanto à sua existência no pool de strings e será criado, uma vez que não existe no o caso acima.
fonte
Embora pareça o mesmo do ponto de vista dos programadores, ele tem um grande impacto no desempenho. Você deseja usar o primeiro formulário quase sempre.
fonte
Ele irá verificar se o pool constante de String já contém String "hello"? Se presente, ele não adicionará uma entrada no pool constante de String. Se não estiver presente, ele adicionará uma entrada no pool constante de String.
Um objeto será criado em uma área de memória de heap e
str
pontos de referência para o objeto criado no local da memória de heap.se você deseja fazer
str
referência ao objeto de ponto que contém no pool constante de String, é necessário chamar explicitamentestr.intern();
Ele irá verificar se o pool constante de String já contém String "hello"? Se presente, ele não adicionará uma entrada no pool constante de String. Se não estiver presente, ele adicionará uma entrada no pool constante de String.
Nos dois casos acima, a
str
referência aponta para String"world"
presente no pool Constant.fonte
Quando você armazena uma String como
diretamente, a JVM cria um objeto String com o preço especificado durante um bloco de memória separado chamado pool constante de String.
E sempre que temos a tendência de tentar produzir outra String como
A JVM verifica se existe algum objeto String com preço constante no conjunto de constantes String, se houver, em vez de criar um novo objeto, a JVM atribui a referência do objeto existente à nova variável.
E quando armazenamos String como
usando a nova palavra-chave, um novo objeto com o preço especificado é criado, independentemente do conteúdo do pool constante de String.
fonte