Existem duas formas de criação de objetos string em Java, uma é uma forma literal, como String str = "droid";, e a outra é usar new, um método padrão de construção de objetos, como String str = new String( "droid");, esses dois métodos são frequentemente usados ao escrever código, especialmente o método literal. No entanto, existem algumas diferenças no desempenho e no uso de memória entre essas duas implementações. Tudo isso se deve ao fato de que, para reduzir a criação repetida de objetos string, a JVM mantém uma memória especial. Essa memória é chamada de pool constante de string ou pool literal de string.
Princípio de funcionamento
Quando um objeto string é criado na forma de um literal no código, a JVM verificará primeiro o literal. Se houver uma referência a um objeto string com o mesmo conteúdo no conjunto de constantes de string, a referência será retornada, caso contrário. uma nova string será criada. O objeto é criado, esta referência é colocada no conjunto de constantes de string e a referência é retornada.
Dê um exemplo
Formulário de criação literal
Copie o código do código da seguinte forma:
String str1 = "droide";
A JVM detecta este literal. Aqui pensamos que não existe nenhum objeto cujo conteúdo seja droid. A JVM não consegue encontrar a existência de um objeto string com o conteúdo do droid por meio do pool de constantes de string, então ela criará o objeto string, então colocará a referência do objeto recém-criado no pool de constantes de string e retornará a referência para o variável str1.
Se houver um trecho de código como este a seguir
Copie o código do código da seguinte forma:
String str2 = "droide";
Da mesma forma, a JVM ainda precisa detectar esse literal. A JVM pesquisa o pool de constantes de string e descobre que o objeto de string com o conteúdo de "droid" existe, então retorna a referência do objeto de string existente para a variável str2. Observe que um novo objeto string não é recriado aqui.
Para verificar se str1 e str2 apontam para o mesmo objeto, podemos usar este código
Copie o código do código da seguinte forma:
System.out.println(str1 == str2);
O resultado é verdadeiro.
Criar usando novo
Copie o código do código da seguinte forma:
String str3 = new String("droid");
Quando usamos new para construir um objeto string, um novo objeto string será criado independentemente de haver uma referência a um objeto com o mesmo conteúdo no conjunto de constantes de string. Então, usamos o seguinte código para testá-lo,
Copie o código do código da seguinte forma:
String str3 = new String("droid");
System.out.println(str1 == str3);
O resultado é falso como pensávamos, indicando que as duas variáveis apontam para objetos diferentes.
estagiário
Para o objeto string criado usando new acima, se você deseja adicionar a referência deste objeto ao pool de constantes de string, você pode usar o método intern.
Após chamar o estagiário, primeiro verifique se há uma referência ao objeto no conjunto de constantes de string. Se existir, retorne a referência à variável. Caso contrário, adicione a referência e retorne-a à variável.
Copie o código do código da seguinte forma:
String str4 = str3.intern();
System.out.println(str4 == str1);
O resultado de saída é verdadeiro.
Perguntas difíceis
Pré-requisito?
O pré-requisito para a implementação do pool de constantes de string é que o objeto String em Java seja imutável, o que pode garantir com segurança que várias variáveis compartilhem o mesmo objeto. Se o objeto String em Java for mutável e uma operação de referência alterar o valor do objeto, outras variáveis também serão afetadas. Obviamente, isso não é razoável.
referência ou objeto
O problema mais comum é se referências ou objetos são armazenados no conjunto de constantes de string. O pool de constantes de string armazena referências de objetos, não objetos. Em Java, os objetos são criados na memória heap.
Verificação de atualização, muitos comentários recebidos também discutem esse problema, simplesmente verifiquei. Ambiente de verificação:
Copie o código do código da seguinte forma:
22:18:54-androidyue~/Vídeos$ cat /etc/os-release
NOME=Fedora
VERSÃO = "17 (milagre robusto)"
ID=fedora
VERSÃO_ID=17
PRETTY_NAME="Fedora 17 (milagre robusto)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:17"
22:19:04-androidyue~/Vídeos$ versão java
versão java "1.7.0_25"
Ambiente de execução OpenJDK (fedora-2.3.12.1.fc17-x86_64)
VM de servidor OpenJDK de 64 bits (compilação 23.7-b01, modo misto)
Ideia de verificação: O seguinte programa Java lê um arquivo de vídeo com tamanho de 82M e executa operações internas na forma de strings.
Copie o código do código da seguinte forma:
22:01:17-androidyue~/Vídeos$ ll -lh |
-rw-rw-r--.1 androidyue androidyue 82M 20 de outubro de 2013 por que_to_learn.mp4
Código de verificação
Copie o código do código da seguinte forma:
importar java.io.BufferedReader;
importar java.io.FileNotFoundException;
importar java.io.FileReader;
importar java.io.IOException;
classe pública TestMain {
string estática privada fileContent;
public static void main(String[] args) {
fileContent = readFileToString(args[0]);
if (nulo! = arquivoConteúdo) {
fileContent = fileContent.intern();
System.out.println("Não Nulo");
}
}
string estática privada readFileToString (arquivo de string) {
Leitor BufferedReader = null;
tentar {
leitor = novo BufferedReader(novo FileReader(arquivo));
Buff de StringBuffer = new StringBuffer();
Linha de corda;
while ((linha = leitor.readLine()) != null) {
buff.append(linha);
}
retornar buff.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finalmente {
if (null != leitor) {
tentar {
leitor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
retornar nulo;
}
}
Como o conjunto de constantes de string existe na geração permanente na memória heap, ele é aplicável antes do Java8. Verificamos isso definindo a geração permanente para um valor muito pequeno. Se o objeto string existir no conjunto de constantes de string, o erro de espaço permgen java.lang.OutOfMemoryError será inevitavelmente gerado.
Copie o código do código da seguinte forma:
java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4
A execução do programa de prova não gerou OOM. Na verdade, isso não pode provar muito bem se objetos ou referências estão armazenados.
Mas isso pelo menos prova que o objeto de conteúdo real char[] da string não está armazenado no pool de constantes da string. Nesse caso, na verdade não é tão importante se o conjunto de constantes de string armazena objetos de string ou referências a objetos de string. Mas pessoalmente ainda prefiro guardá-lo como referência.
Vantagens e Desvantagens
A vantagem do pool de constantes de strings é reduzir a criação de strings com o mesmo conteúdo e economizar espaço de memória.
Se insistimos em falar das desvantagens, é que o tempo de computação da CPU é sacrificado em troca de espaço. O tempo de cálculo da CPU é usado principalmente para descobrir se há uma referência a um objeto com o mesmo conteúdo no conjunto de constantes de string. Porém, sua implementação interna é HashTable, portanto o custo de cálculo é baixo.
Reciclagem de GC?
Como o conjunto de constantes de string contém referências a objetos de string compartilhados, isso significa que esses objetos não podem ser reciclados?
Em primeiro lugar, os objectos partilhados em questão são geralmente relativamente pequenos. Pelo que eu sei, esse problema existia em versões anteriores, mas com a introdução de referências fracas, esse problema deveria desaparecer agora.
Em relação a esse assunto, você pode aprender mais sobre este artigo interno Strings: Java Glossary
uso interno?
O pré-requisito para usar o estagiário é que você saiba que realmente precisa usá-lo. Por exemplo, temos milhões de registros aqui, e um determinado valor no registro é Califórnia, EUA, muitas vezes. Não queremos criar milhões desses objetos de string. Podemos usar intern para manter apenas uma cópia na memória. Pode. Para uma compreensão mais aprofundada do estagiário, consulte Análise aprofundada de String#intern.
Sempre há exceções?
Você sabia que o código a seguir criará vários objetos string e salvará várias referências no pool de constantes string?
Copie o código do código da seguinte forma:
Teste de string = "a" + "b" + "c";
A resposta é que apenas um objeto é criado e apenas uma referência é salva no conjunto de constantes. Podemos descobrir usando javap para descompilar e dar uma olhada.
Copie o código do código da seguinte forma:
17:02 $ javap -c TesteInternedPoolGC
Compilado de "TestInternedPoolGC.java"
classe pública TestInternedPoolGC estende java.lang.Object{
public TestInternedPoolGC();
Código:
0: aload_0
1: invocar especial #1; //Método java/lang/Object."<init>":()V
4: retorno
public static void main(java.lang.String[]) lança java.lang.Exception;
Código:
0: ldc#2; //String abc
2: uma loja_1
3: retorno
Você viu que durante a compilação esses três literais foram combinados em um? Na verdade, esta é uma otimização que evita a criação de objetos string redundantes e não causa problemas de emenda de strings. Em relação à emenda de string, você pode visualizar os detalhes do Java: Emenda de string.