Com relação às questões desta série, todos que estudam Java devem entendê-las. Claro, não importa se você aprende Java apenas por diversão. Se você acha que ultrapassou o nível iniciante, mas não entende bem essas questões, adicione-se à equipe iniciante.
Pergunta 1: O que estou afirmando?
String s = "Olá, mundo!";
Muitas pessoas já fizeram isso, mas o que exatamente declaramos? A resposta geralmente é: uma String com o conteúdo “Olá, mundo!”. Tais respostas vagas são muitas vezes a fonte de conceitos pouco claros. Se você desse uma resposta precisa, provavelmente metade das pessoas responderia errado.
Esta instrução declara uma referência a um objeto, denominado "s", que pode apontar para qualquer objeto do tipo String. Atualmente, ela aponta para o objeto do tipo String "Hello world!". Isto é o que realmente aconteceu. Não declaramos um objeto String, apenas declaramos uma variável de referência que só pode apontar para o objeto String. Então, se após a declaração de agora há pouco, você executar outra frase:
String string = s;
Declaramos outra referência que só pode apontar para o objeto String, chamada string. Nenhum segundo objeto String ainda aponta para o objeto original, ou seja, aponta para o mesmo objeto que s.
Pergunta 2: Qual é a diferença entre o método "==" e o método equals?
O operador == é usado especificamente para comparar os valores das variáveis para igualdade. A coisa mais fácil de entender é:
Copie o código do código da seguinte forma:
int a=10;
internob=10;
Então a==b será verdadeiro.
Mas o que é difícil de entender é:
Copie o código do código da seguinte forma:
String a=new String("foo");
String b = nova String("foo");
Então a==b retornará falso.
De acordo com o post anterior, variáveis de objeto são na verdade referências, e seus valores apontam para o endereço de memória onde o objeto está localizado, e não para o objeto em si. Tanto a quanto b usam o operador new, o que significa que duas strings com o conteúdo “foo” serão geradas na memória. Como são “duas”, elas estão naturalmente localizadas em endereços de memória diferentes. Os valores de aeb são na verdade os valores de dois endereços de memória diferentes, portanto, usando o operador "==", o resultado será falso. É verdade que os objetos apontados por a e b possuem o conteúdo "foo" e deveriam ser "iguais", mas o operador == não envolve comparação do conteúdo do objeto.
A comparação do conteúdo do objeto é exatamente o que o método equals faz.
Dê uma olhada em como o método equals do objeto Object é implementado:
Copie o código do código da seguinte forma:
booleano é igual(Objeto o){
retorne isto==o;
}
Objetos objetos usam o operador == por padrão. Portanto, se sua classe criada por você mesmo não substituir o método equals, sua classe obterá o mesmo resultado usando equals e ==. Também pode ser visto que o método equals de Object não atinge o objetivo que o método equals deveria atingir: comparar se o conteúdo de dois objetos é igual. Como a resposta deve ser determinada pelo criador da classe, Object deixa essa tarefa para o criador da classe.
Dê uma olhada em uma aula extrema:
Copie o código do código da seguinte forma:
Monstro de classe{
conteúdo de string privado;
...
boolean equals(Objeto outro){ return true;}
}
Eu substituí o método equals. Esta implementação faz com que as comparações entre instâncias Monster sempre retornem verdadeiras, independentemente de seu conteúdo.
Portanto, quando você usa o método equals para determinar se o conteúdo de um objeto é igual, não tome isso como certo. Porque talvez você pense que eles são iguais, mas o autor desta classe não pensa assim, e a implementação do método equals da classe é controlada por ele. Se você precisar usar o método equals ou qualquer coleção baseada em código hash (HashSet, HashMap, HashTable), verifique o documento java para confirmar como a lógica equals desta classe é implementada.
Pergunta 3: String mudou?
Não. Como String foi projetada para ser uma classe imutável, todos os seus objetos são objetos imutáveis. Por favor, observe o seguinte código:
Copie o código do código da seguinte forma:
Strings = "Olá";
s = s + "mundo!";
O alvo apontado por s mudou? Esta conclusão pode ser facilmente derivada da conclusão do primeiro artigo desta série. Vamos ver o que aconteceu. Neste código, s apontou originalmente para um objeto String com o conteúdo "Hello" e, em seguida, realizamos uma operação + em s. O objeto apontado por s mudou? A resposta é não. Neste momento, s não aponta mais para o objeto original, mas para outro objeto String com o conteúdo "Olá, mundo!". O objeto original ainda existe na memória, mas a variável de referência s não aponta mais para ele.
Através da explicação acima, podemos facilmente tirar outra conclusão. Se as strings forem frequentemente modificadas de várias maneiras, ou modificadas de forma imprevisível, então usar String para representar uma string causará muita sobrecarga de memória. Como o objeto String não pode ser alterado após ser criado, um objeto String é necessário para representar cada string diferente. Neste momento, você deve considerar o uso da classe StringBuffer, que permite modificação, em vez de gerar um novo objeto para cada string diferente. Além disso, a mudança de política entre estes dois tipos é muito simples.
Ao mesmo tempo, também podemos saber que se você quiser usar uma string com o mesmo conteúdo, não será necessário criar uma nova String todas as vezes. Por exemplo, se quisermos inicializar uma variável de referência String chamada s no construtor e defini-la com o valor inicial, devemos fazer o seguinte:
Copie o código do código da seguinte forma:
demonstração de classe pública {
strings privadas;
…
demonstração pública {
s = “Valor Inicial”;
}
…
}
Em vez de s = new String("Valor Inicial");
Este último chamará o construtor sempre para gerar um novo objeto, que tem baixo desempenho e grande consumo de memória e não tem sentido. Como o objeto String não pode ser alterado, apenas um objeto String pode ser usado para representar uma string com o mesmo conteúdo. . Em outras palavras, se você chamar o construtor acima várias vezes para criar vários destinos, seus atributos do tipo String apontarão todos para o mesmo destino.
A conclusão acima também se baseia no fato de que, para constantes de string, se o conteúdo for o mesmo, o Guangzhou Java Training acredita que elas representam o mesmo objeto String. Chamar o construtor com a palavra-chave new sempre criará um novo alvo, independentemente de o conteúdo ser o mesmo.
Quanto ao motivo pelo qual a classe String deve ser descrita como uma classe imutável, isso é determinado por seu propósito. Na verdade, não apenas String, mas também muitas classes da biblioteca de classes padrão Java são imutáveis. Ao desenvolver um sistema, às vezes precisamos descrever classes imutáveis para transmitir um conjunto de valores relacionados, o que também é uma manifestação do pensamento orientado para objetivos. Classes imutáveis têm algumas vantagens. Por exemplo, como sua finalidade é somente leitura, não haverá problemas com acesso simultâneo por vários threads. Claro, também existem algumas deficiências. Por exemplo, cada situação diferente necessita de um objeto para representá-la, o que pode causar problemas funcionais. Portanto, a biblioteca de classes padrão Java também fornece uma versão variável, chamada StringBuffer.