Imutabilidade de string, análise de código-fonte de cache longo e perguntas da entrevista
Todos estão familiarizados com String e Long. Agora vamos dar uma olhada na implementação do código-fonte subjacente de String e Long em combinação com cenários de trabalho reais. Veja se há algum ponto que precisamos prestar atenção ao usá-los e resumir a que essas APIs são aplicáveis. Cenas.
One: String
1.1. Imutabilidade
Frequentemente vemos essas perguntas na entrevista: Fale brevemente sobre a diferença entre String, StringBuilder e StringBuffer. Dentre elas, a String é diferente das outras duas, uma vez que o valor da String é inicializado não pode ser alterado, se for modificado, será uma nova classe. Vamos dar uma olhada no seguinte trecho de código: Embora "ssssss" seja gerado no final, parece que o valor de String foi modificado.
String str = "aaa";
str = "ssssss";
System.out.println(str);
Na verdade, podemos ver intuitivamente por meio de Debug que o valor de String não foi modificado.
A princípio, o endereço de memória apontado por str é 527 e, após uma rodada de atribuição, o endereço de memória apontado por str torna-se 529. Em outras palavras, a atribuição aparentemente simples de str = "ssssss" na verdade aponta a referência de str para a nova String.
Agora vamos olhar o motivo do código-fonte de String
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
Podemos ver no código-fonte da String:
- String é modificado por final, indicando que a classe String nunca será herdada, ou seja, nenhum método de operação em String será sobrescrito por herança ;
- Os dados armazenados em String são um valor de array char. Descobrimos que o valor também é modificado por final, o que significa que uma vez que o valor é atribuído, o endereço de memória é absolutamente impossível de modificar e a permissão do valor é privada, absolutamente inacessível de fora e String não abriu a atribuição de valor Método, então, uma vez que o valor é gerado, o endereço da memória não pode ser modificado ;
Os dois pontos acima são a razão da imutabilidade de String. Ele aproveita ao máximo as características da palavra-chave final. Se você quiser ser imutável ao personalizar a classe, também pode imitar essas duas operações de String.
1.2, julgamento de igualdade
Temos duas maneiras de julgar igualdade, equals e equalsIgnoreCase. Quando o último for considerado igual, o caso será ignorado. Se você for solicitado a escrever a lógica para julgar a igualdade de duas Strings, como escrevê-la, vamos dar uma olhada no código-fonte de iguais:
public boolean equals(Object anObject) {
// 判断内存地址是否相同
if (this == anObject) {
return true;
}
// 待比较的对象是否是 String,如果不是 String,直接返回不相等
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
// 两个字符串的长度是否相等,不等则直接返回不相等
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 依次比较每个字符是否相等,若有一个不等,直接返回不相等
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Como pode ser visto no código-fonte de iguais, a lógica é muito clara e o código equivalente é escrito completamente com base na estrutura subjacente de String. Isso também nos fornece uma maneira de pensar: se alguém pergunta como julgar se os dois são iguais, podemos começar a partir da estrutura subjacente dos dois, para que possamos pensar rapidamente em uma ideia prática e método, assim como a String subjacente A estrutura de dados é a mesma do array char. Ao julgar a igualdade, apenas compare os caracteres no array char um por um para ver se eles são iguais.
Dois: Longo
2.1, cache
Estamos mais preocupados com o problema de cache de Long. Long implementou um mecanismo de cache que armazena em cache todos os valores Long de -128 a 127. Se for um valor Long neste intervalo, ele não será inicializado, mas Retire do cache, o código-fonte de inicialização do cache é o seguinte:
private static class LongCache {
private LongCache(){
}
// 缓存,范围从 -128 到 127,+1 是因为有个 0
static final Long cache[] = new Long[-(-128) + 127 + 1];
// 容器初始化时,进行加载
static {
// 缓存 Long 值,注意这里是 i - 128 ,所以再拿的时候就需要 + 128
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
Três: perguntas da entrevista
3.1. Por que é recomendado usar mais o método valueOf e menos o método parseLong ao usar Long?
Como o próprio Long tem um mecanismo de cache que armazena Longs no intervalo de -128 a 127, o método valueOf obterá o valor do cache. Se o cache for atingido, ele reduzirá a sobrecarga de recursos. O método parseLong não tem esse mecanismo.
3.2. Por que todo mundo diz que String é imutável?
Se String e o array char que contém os dados forem modificados pela palavra-chave final, eles serão imutáveis. Para obter detalhes, consulte o acima.
Três: Resumo
String e Long são usados com frequência em nosso trabalho.No processo de entrevista, o examinador também gosta de fazer algumas perguntas práticas para verificar nossa proficiência.