Olá! Hoje falaremos sobre um tópico muito importante e interessante, a saber, comparar objetos entre si equals() em Java. E, de fato, em que casos em Java o Objeto A será igual ao Objeto B ? Vamos tentar escrever um exemplo:
public class Car {
String model;
int maxSpeed;
public static void main(String[] args) {
Car car1 = new Car();
car1.model = "Ferrari";
car1.maxSpeed = 300;
Car car2 = new Car();
car2.model = "Ferrari";
car2.maxSpeed = 300;
System.out.println(car1 == car2);
}
}
Saída do console:
false
Ok, pare. Por que, de fato, esses dois carros não são iguais? Demos a eles as mesmas propriedades, mas o resultado da comparação é falso. A resposta é simples. O operador ==
compara não as propriedades dos objetos, mas os links. Mesmo que dois objetos tenham 500 propriedades idênticas, o resultado da comparação ainda será falso. Afinal, os links car1
apontam car2
para dois objetos diferentes , para dois endereços diferentes. Imagine uma situação comparando pessoas. Provavelmente existe uma pessoa no mundo que tem o mesmo nome, cor dos olhos, idade, altura, cor do cabelo, etc. Ou seja, vocês são semelhantes em muitos aspectos, mas ainda assim não são gêmeos e, principalmente, não são a mesma pessoa. O operador aplica aproximadamente a mesma lógica ==
quando o usamos para comparar dois objetos. Mas e se você precisar de uma lógica diferente em seu programa? Por exemplo, se o seu programa simular análise de DNA. Ela deve comparar o código de DNA de duas pessoas e determinar que são gêmeas.
public class Man {
int dnaCode;
public static void main(String[] args) {
Man man1 = new Man();
man1.dnaCode = 1111222233;
Man man2 = new Man();
man2.dnaCode = 1111222233;
System.out.println(man1 == man2);
}
}
Saída do console:
false
É lógico que o resultado foi o mesmo (afinal não mudamos nada), mas agora não estamos satisfeitos! Na verdade, na vida real, a análise de DNA é uma garantia de cem por cento de que estamos diante de gêmeos. Mas nosso programa e operador ==
nos dizem o contrário. Como podemos mudar esse comportamento e garantir que, se os testes de DNA corresponderem, o programa produzirá o resultado correto? Para tanto, foi criado um método especial em Java - equals() .
Método Equals() em Java
Assim como o métodotoString()
que discutimos anteriormente, equals() pertence à classe, Object
a classe mais importante em Java, da qual todas as outras classes são derivadas. No entanto, equals() em si não mudará o comportamento do nosso programa de forma alguma:
public class Man {
String dnaCode;
public static void main(String[] args) {
Man man1 = new Man();
man1.dnaCode = "111122223333";
Man man2 = new Man();
man2.dnaCode = "111122223333";
System.out.println(man1.equals(man2));
}
}
Saída do console:
false
Exatamente o mesmo resultado, então por que esse método é necessário? :/ É simples. O fato é que agora utilizamos esse método conforme ele é implementado na própria classe Object
. E se entrarmos no código da classe Object
e vermos como esse método é implementado nela e o que ele faz, veremos:
public boolean equals(Object obj) {
return (this == obj);
}
Esta é a razão pela qual o comportamento do nosso programa não mudou! Dentro do método equals() da classe Object
encontra-se a mesma comparação de referência, ==
. Mas o truque deste método é que podemos substituí-lo. Substituir significa escrever seu próprio método equals() em nossa classe Man
e fazer com que ele se comporte da maneira que desejamos! Agora não estamos satisfeitos com o fato de a verificação man1.equals(man2)
fazer essencialmente a mesma coisa que man1 == man2
. Aqui está o que faremos nesta situação:
public class Man {
int dnaCode;
public boolean equals(Man man) {
return this.dnaCode == man.dnaCode;
}
public static void main(String[] args) {
Man man1 = new Man();
man1.dnaCode = 1111222233;
Man man2 = new Man();
man2.dnaCode = 1111222233;
System.out.println(man1.equals(man2));
}
}
Saída do console:
true
Um resultado completamente diferente! Ao escrever nosso próprio método equals() em vez do método padrão, alcançamos o comportamento correto: agora, se duas pessoas têm o mesmo código de DNA, o programa nos diz: “A análise de DNA mostrou que são gêmeos” e retorna verdadeiro! Ao substituir o método equals() em suas classes, você pode criar facilmente a lógica de comparação de objetos necessária. Abordamos a comparação de objetos apenas em termos gerais. Ainda teremos uma grande palestra separada sobre este tópico (você pode lê-la rapidamente agora, se estiver interessado).
Comparação de strings em Java - comparação de strings
Por que tratamos as comparações de strings separadamente de todo o resto? Bem, na verdade, as linhas de programação são uma história totalmente diferente. Em primeiro lugar, se pegarmos todos os programas Java escritos pela humanidade, cerca de 25% dos objetos neles contidos são compostos por eles. Portanto, este tema é muito importante. Em segundo lugar, o processo de comparação de strings é bastante diferente de outros objetos. Vejamos um exemplo simples:public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = new String("JavaRush is the best site to learn Java!");
System.out.println(s1 == s2);
}
}
Saída do console:
false
Mas por que falso? As linhas são exatamente iguais, palavra por palavra :/ Você pode assumir: isso ocorre porque o operador ==
compara referências! Afinal, s1
eles s2
possuem endereços diferentes na memória. Se esse pensamento lhe ocorreu, então vamos refazer nosso exemplo:
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
System.out.println(s1 == s2);
}
}
Agora também temos dois links, mas o resultado mudou para o oposto: Saída do console:
true
Completamente confuso? :) Vamos descobrir. Na verdade , o operador ==
compara endereços na memória. Esta regra sempre funciona e não há necessidade de duvidar dela. Isso significa que se s1 == s2
retornar verdadeiro, essas duas strings terão o mesmo endereço na memória. E de fato é! É hora de se familiarizar com uma área de memória especial para armazenar strings - o pool de strings ( String pool
) O pool de strings é uma área para armazenar todos os valores de string que você cria em seu programa. Para que foi criado? Conforme mencionado anteriormente, as strings ocupam uma grande parte de todos os objetos. Em qualquer programa grande, muitas linhas são criadas. Para economizar memória, é isso que é necessário String Pool
- uma linha com o texto que você precisa é colocada ali e, no futuro, os links recém-criados referem-se à mesma área de memória, não há necessidade de alocar memória adicional a cada vez. Cada vez que você escreve String = “........”
, o programa verifica se existe uma linha com esse texto no conjunto de strings. Se houver, não será criado um novo. E o novo link apontará para o mesmo endereço no conjunto de strings onde esta string está armazenada. Portanto, quando escrevemos no programa
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
o link s2
aponta exatamente para o mesmo lugar que s1
. O primeiro comando criou uma nova linha no conjunto de strings com o texto que precisávamos e, quando chegou ao segundo, simplesmente se referiu à mesma área de memória que s1
. Você pode fazer pelo menos mais 500 linhas com o mesmo texto, o resultado não mudará. Parar. Mas por que esse exemplo não funcionou para nós antes?
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = new String("JavaRush is the best site to learn Java!");
System.out.println(s1 == s2);
}
}
Acho que, intuitivamente, você já adivinha qual é o motivo :) Tente adivinhar antes de continuar lendo. Você pode ver que essas duas linhas foram criadas de forma diferente. Um é com a ajuda do operador new
e o segundo é sem ele. Esta é precisamente a razão. O operador new, ao criar um objeto, aloca forçosamente uma nova área na memória para ele . E a linha criada com new
, não termina em String Pool
: ela se torna um objeto separado, mesmo que seu texto seja exatamente igual à mesma linha de String Pool
'a. Isto é, se escrevermos o seguinte código:
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
String s3 = new String("JavaRush is the best site to learn Java!");
}
}
Na memória ficará assim: E toda vez que um novo objeto for criado, new
uma nova área será alocada na memória, mesmo que o texto dentro das novas linhas seja o mesmo! Parece que resolvemos o operador ==
, mas e o nosso novo amigo - o método equals()?
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = new String("JavaRush is the best site to learn Java!");
System.out.println(s1.equals(s2));
}
}
Saída do console:
true
Interessante. Sabemos exatamente o que s1
e s2
apontamos para diferentes áreas da memória. Mesmo assim, o método equals() diz que eles são iguais. Por que? Lembre-se, acima dissemos que o método equals() pode ser substituído em sua classe para comparar objetos da maneira que você precisa? Foi o que fizeram com a aula String
. Possui um método equals() substituído. E não compara links, mas sim a sequência de caracteres em strings. E se o texto nas strings for o mesmo, não importa como elas foram criadas e onde estão armazenadas: no pool de strings ou em uma área de memória separada. O resultado da comparação será verdadeiro. A propósito, Java permite comparar strings corretamente, sem diferenciar maiúsculas de minúsculas. Numa situação normal, se você escrever uma das linhas, por exemplo, em maiúsculas, o resultado da comparação será falso:
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = new String("JAVARUSH - ЛУЧШИЙ САЙТ ДЛЯ ИЗУЧЕНИЯ JAVA!");
System.out.println(s1.equals(s2));
}
}
Saída do console:
false
Para este caso, a classe String
possui um método equalsIgnoreCase()
. Se o principal na sua comparação for a sequência de caracteres específicos, e não o caso deles, você poderá usá-lo. Por exemplo, isto será útil ao comparar dois endereços de e-mail:
public class Main {
public static void main(String[] args) {
String address1 = "Moscow, Academician Korolev street, 12";
String address2 = new String("Г. МОСКВА, УЛ. АКАДЕМИКА КОРОЛЕВА, ДОМ 12");
System.out.println(address1.equalsIgnoreCase(address2));
}
}
Neste caso, é óbvio que se trata do mesmo endereço, pelo que utilizar o método equalsIgnoreCase()
será a decisão acertada.
Método String.intern()
A classeString
tem outro método complicado - intern()
; O método intern()
funciona diretamente com String Pool
'om. Se você chamar um método intern()
em uma string, ele:
- Procura ver se há uma string com este texto no conjunto de strings
- Se houver, retorna um link para ele no pool
- Caso contrário, ele coloca uma linha com este texto no conjunto de strings e retorna um link para ele.
intern()
à referência de string que foi criada via new, podemos compará-lo com a referência de string de String Pool
'a por meio do ==
.
public class Main {
public static void main(String[] args) {
String s1 = "JavaRush is the best site to learn Java!";
String s2 = new String("JavaRush is the best site to learn Java!");
System.out.println(s1 == s2.intern());
}
}
Saída do console:
true
Anteriormente, quando os comparávamos sem intern()
, o resultado era falso. Agora o método intern()
verificava se havia uma linha com o texto “JavaRush – o melhor site para aprender Java!” no conjunto de cordas. Claro que está lá: nós o criamos quando escrevemos
String s1 = "JavaRush is the best site to learn Java!";
Foi verificado que a referência s1
e a referência retornada pelo método s2.intern()
apontam para a mesma área da memória, e, claro, apontam :) Para resumir, lembre-se e use a regra principal: Para comparar strings, SEMPRE use o equals() método! Ao comparar strings, quase sempre você quer dizer comparar seu texto, não links, áreas de memória e assim por diante. O método equals() faz exatamente o que você precisa. Aqui estão alguns links para você estudar por conta própria:
GO TO FULL VERSION