Várias piscinas constantes
- Vamos dar uma olhada no diagrama de estrutura geral da máquina virtual
.
piscina constante de classe
- diagrama de estrutura de arquivo de classe
- Depois que a classe java é compilada, gere
.class文件
Citado
class文件
além de conter as versões da classe, campos, métodos e informações de descrição da interface, há uma mensagem常量池(constant pool table)
, para armazenar várias gerações do compilador字面量(Literal)
e符号引用(Symbolic References)
.
Literal : conceito constante, como textoStrings"abc"
, valores constantes declarados como finais, etc..
Referência de símbolo :Um conjunto de símbolos para descrever o alvo referenciado. O símbolo pode ser qualquer forma de quantidade literal, desde que possa ser usado para localizar o alvo sem ambigüidade. (A distinção entre referência direta: referência direta é geralmente um ponteiro local para uma área de método, um deslocamento relativo ou um identificador que pode localizar indiretamente o destino).
As referências de símbolo geralmente incluem os três tipos de constantes a seguir:
- Nomes totalmente qualificados de classes e interfaces
- Nome do campo e descritor
- Nome e descritor do método
Class Data
Existe na área do método (a implementação da área do método 1.8 é um metaespaço, que anteriormente era uma geração permanente).
Pool de constantes de string
字符串常量池
, Também conhecida como字符串字面量池(String Literal Pool)
,字符串池(String Pool)
,全局字符串池
.
O carregamento da classe está completo, após verificação, após a fase de preparaçãoNa instância do objeto de string de caracteres gerado pela pilha , e então estesEndereço de referência da instância do objeto stringSalvar em字符串池
.- Em
HotSpot VM
Lane, a字符串池
função implementada é umaStringTable
classe, que é uma tabela hash, que é armazenada驻留字符串
(na parte de aspas duplas) da referência ,Em vez da própria instância de string residente, a própria instância ainda está no heap. Portanto, esses são exemplos dessa stringStringTable
depois que a referência recebeu o equivalente de驻留字符串
identidade. EstaStringTable
em cadaHotSpot VM
apenas uma instância é compartilhada por todas as classes. - O pool de constantes de string está no heap (na área do método antes de 1.7)
Pool constante de tempo de execução
- Quando a classe é carregada na memória, o conteúdo
jvm
éclass常量池
armazenado no pool de constantes de runtime, ou seja, cada classe possui um pool de constantes de runtime.class常量池
Os dados serão analisados e carregados no pool de constantes de tempo de execução.
class
O pool de constantes armazena literais e referências de símbolo e, após a análise , as referências de símbolo são substituídas por referências diretas. O processo de análise irá consultar o pool de constantes de string, que é o acimaStringTable
, para garantir que a string referenciada pelo pool de constantes em tempo de execução seja consistente com a string referenciada no pool de strings global.
- O conjunto de constantes de tempo de execução está na área do método.
Alguns problemas com o pool de constantes de string
@Test
public void test() {
String str1 = "abc";
String str2 = new String("def");
String str3 = "abc";
String str4 = str2.intern();
String str5 = "def";
System.out.println(str1 == str3); //true
System.out.println(str2 == str4);//false
System.out.println(str4 == str5);//true
}
"abc"
A instância no heap já existe quando a classe é carregada e a referência"abc"
noStringTable
é retornada diretamente .new String("def")
O espaço de memória é recém-aplicado e uma nova instância de string é criada.O valor é"def"
retornado ao endereço."def"
O mesmo já existeStringTable
."abc"
NaStringTable
verdade, o retorno diretoStringTable
em uma referência.intern()
: SeStringTable
não houver referência à string, adicione-a."def"
A referência retornou ."def"
NaStringTable
verdade, o retorno diretoStringTable
em uma referência.
@Test
public void test() {
//此行代码执行的底层执行过程是
//创建临时StringBuilder的append方法将"2"和"2"拼接在一块,然后调用toString方法new出"22"
//在StingTable中会有"22"的引用
String str1 = new String("2") + new String("2");
String str2 = "22";
System.out.println(str1 == str2); //false
}
@Test
public void test() {
String str1 = "a";
String str2 = "b";
String str3 = "ab";
//同样通过StringBuilder append,new String("ab"),会在StringTable中添加引用
String str4 = str1 + str2;
//编译时常量,在编译后直接能计算出拼接后的字符串值,不需要再运行时创建临时StringBuilder对象。
//返回StringTable中的"ab"引用
String str5 = "a" + "b";
System.out.println(str3 == str4); // false
System.out.println(str3 == str4.intern()); // true
System.out.println(str3 == str5);// true
}
Caso especial
public static final String A; // 常量A
public static final String B; // 常量B
static {
A = "ab";
B = "cd";
}
public static void tes() {
// 将两个常量用+连接对s进行初始化
String s = A + B;
String t = "abcd";
System.out.println(s == t);//false
}
Embora A e B sejam definidos como constantes, eles não são atribuídos imediatamente. Antes de o valor de s ser calculado, quando eles são atribuídos e qual valor é atribuído, todas são variáveis. Portanto, antes de A e B serem atribuídos, suas propriedades são semelhantes a uma variável. Então s não pode ser determinado em tempo de compilação, mas só pode ser criado em tempo de execução.