O que é String Interning em Java, quando devo usá-lo e por quê ?
java
string
string-interning
saplingPro
fonte
fonte
String a = new String("abc");
String b = new String("abc");
entãoa.intern() == b.intern()
String.intern()
dependemClassLoader
, ou seja, fazer diferente carregador de classe de criação de "diferentes"String
s, causando diferentesintern
s?Respostas:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern ()
Basicamente, fazer String.intern () em uma série de strings garantirá que todas as strings com o mesmo conteúdo compartilhem a mesma memória. Portanto, se você tiver uma lista de nomes onde 'john' aparece 1000 vezes, internando você garante que apenas um 'john' seja realmente alocado de memória.
Isso pode ser útil para reduzir os requisitos de memória do seu programa. Mas lembre-se de que o cache é mantido pela JVM no conjunto de memórias permanentes, que geralmente é limitado em tamanho comparado ao heap, portanto, você não deve usar intern se não tiver muitos valores duplicados.
Mais sobre restrições de memória do uso de intern ()
- De: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
Do JDK 7 (quero dizer no HotSpot), algo mudou.
- Do Java SE 7 Recursos e Aprimoramentos
Atualização: cadeias internas são armazenadas no heap principal a partir do Java 7 em diante. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes
fonte
char[]
vez deString
texto confidencial e zerá-lo assim que não for mais necessário.Existem algumas perguntas de "entrevista cativante", como por que você é igual! se você executar o trecho de código abaixo.
Se você deseja comparar Strings, você deve usar
equals()
. O texto acima será impresso igual porque otestString
já está internado para você pelo compilador. Você pode internar as seqüências de caracteres usando o método intern, como é mostrado nas respostas anteriores ....fonte
equals
método Você pode adicionar umanew String()
comparação para mostrar a distinção mais claramente.JLS
O JLS 7 3.10.5 o define e fornece um exemplo prático:
JVMS
O JVMS 7 5.1 diz que a internação é implementada de maneira mágica e eficiente com uma
CONSTANT_String_info
estrutura dedicada (ao contrário da maioria dos outros objetos que possuem representações mais genéricas):Bytecode
Vamos descompilar alguns bytecode do OpenJDK 7 para ver a internação em ação.
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
Atualização para Java 8 ou mais . No Java 8, o espaço PermGen (Geração Permanente) é removido e substituído pelo Meta Space. A memória do conjunto de cadeias é movida para o heap da JVM.
Comparado com o Java 7, o tamanho do pool de String é aumentado no heap. Portanto, você tem mais espaço para seqüências de caracteres internalizadas, mas possui menos memória para todo o aplicativo.
Mais uma coisa, você já sabia que, ao comparar 2 (referências de) objetos em Java, '
==
' é usado para comparar a referência de objeto 'equals
', é usado para comparar o conteúdo do objeto.Vamos verificar este código:
Resultado:
value1 == value2
---> truevalue1 == value3
---> falsevalue1.equals(value3)
---> truevalue1 == value3.intern()
---> trueÉ por isso que você deve usar '
equals
' para comparar objetos 2 String. E é assim queintern()
é útil.fonte
A internação de strings é uma técnica de otimização do compilador. Se você tiver dois literais de seqüência de caracteres idênticos em uma unidade de compilação, o código gerado garantirá que haja apenas um objeto de seqüência de caracteres criado para toda a instância desse literal (caracteres entre aspas duplas) dentro do assembly.
Eu sou de fundo C #, então eu posso explicar, dando um exemplo disso:
saída das seguintes comparações:
Nota1 : Os objetos são comparados por referência.
Nota2 : typeof (int) .Name é avaliado pelo método de reflexão para que não seja avaliado em tempo de compilação. Aqui essas comparações são feitas em tempo de compilação.
Análise dos resultados: 1) verdadeiro porque ambos contêm o mesmo literal e, portanto, o código gerado terá apenas um objeto que faz referência a "Int32". Ver nota 1 .
2) true porque o conteúdo de ambos os valores é verificado, o mesmo.
3) FALSE porque str2 e obj não possuem o mesmo literal. Ver nota 2 .
fonte
fonte
No livro Deshmukh do OCP Java SE 11 Programmer, encontrei a explicação mais fácil para Interning, que foi a seguinte: Como as strings são objetos e como todos os objetos em Java sempre são armazenados apenas no espaço de heap, todas as strings são armazenadas no espaço de heap. No entanto, o Java mantém as strings criadas sem usar a nova palavra-chave em uma área especial do espaço de heap, chamada "pool de strings". Java mantém as seqüências criadas usando a nova palavra-chave no espaço de heap regular.
O objetivo do conjunto de strings é manter um conjunto de strings exclusivos. Sempre que você cria uma nova sequência sem usar a nova palavra-chave, o Java verifica se a mesma sequência já existe no conjunto de sequências. Se isso acontecer, Java retornará uma referência ao mesmo objeto String e, se não, Java criará um novo objeto String no conjunto de strings e retornará sua referência. Portanto, por exemplo, se você usar a sequência "olá" duas vezes no seu código, como mostrado abaixo, obterá uma referência para a mesma sequência. Podemos realmente testar essa teoria comparando duas variáveis de referência diferentes usando o operador == , como mostrado no código a seguir:
== O operador simplesmente verifica se duas referências apontam para o mesmo objeto ou não e retorna true se o fizerem. No código acima, str2 obtém a referência ao mesmo objeto String que foi criado anteriormente. No entanto, str3 e str4 obtêm referências a dois objetos String totalmente diferentes. É por isso que str1 == str2 retorna true, mas str1 == str3 e str3 == str4 retornam false. De fato, quando você faz uma nova String ("olá"); dois objetos String são criados em vez de apenas um, se for a primeira vez que a string "hello" é usada em qualquer lugar do programa - um no pool de strings por causa do uso de uma string entre aspas e um no espaço de heap normal porque do uso de nova palavra-chave.
O pool de strings é a maneira do Java de economizar memória de programa, evitando a criação de vários objetos String que contêm o mesmo valor. É possível obter uma string do pool de strings criada com a nova palavra-chave usando o método interno de String. É chamado "interning" de objetos de string. Por exemplo,
fonte