guilherme.chapiewski:
Somente tipos primitivos (int, float, char, etc) são comparados com ==, !=, etc.
Não é bem assim... Você pode utilizar os operadores == e != para comparar variáveis de tipos não primitivos (
[color=blue]variáveis do tipo referência para objeto[/color]). O que acontece é que estes operadores, quando operando sobre referências, verificam se os operandos referenciam um mesmo objeto na memória.
Se tivermos, por exemplo, o seguinte código:
Integer int1 = new Integer(1);
Integer int2 = new Integer(1);
System.out.println(int1 == int2);
Teremos como saída no console:
Isso porque int1 está referenciando um determinado objeto
Integer, que está em algum lugar da memória, e int2 está referenciando um
outro objeto Integer, em outro lugar da memória. Logo, como int1 e int2 "apontam" para objetos distintos na memória, a operação "int1 == in2" retorna
false e, consequentemente, a operação "int1 != int2" retorna
true.
Mas há um porém nessa história, principalmente quanto ao uso de strings. Se fizermos algo como:
String str1 = "blablabla";
String str2 = "blablabla";
System.out.println(str1 == str2);
O console nos mostrara o seguinte:
A priori, isto contradiz o que eu disse até agora. Mas o que acontece no caso dos objetos
String é o seguinte: Por questão de performance, o Java mantém um tipo de "pool" de Strings dentro dos contextos. No exemplo acima, ao invés de o Java alocar na memória dois objetos
String distintos na memória, ele, "vendo" que o
conteúdo das strings são iguais, poupa memória e processamento alocando apenas um objeto
String e fazendo com que este seja referenciado tanto por
str1 quanto por
str2. Você pode pensar que isso pode dar problema, porque uma variável pode alterar o conteúdo do objeto
String e essa alteração se refletir para a(s) outra(s) variáveis. Porém, isso não acontece, pois objetos
String são
imutáveis.
Mas note que esse lance do pool de
String só (e sempre) funciona quando você cria variáveis String e lhes atribui um string literal, como feito no exemplo acima. Para "fugir" do pool de
String (se você achar necessário por algum motivo), você deve intanciar o String explicitamente com o
new:
String str1 = new String("blablabla");
String str2 = new String("blablabla");
System.out.println(str1 == str2);
Neste caso teremos a resposta:
Pois ordenamos, através do
new, que fossem criados objetos String distintos.
guilherme.chapiewski:
Strings são objetos e como todos os outros objetos são comparados através do método equals()
Comparar objetos através do método
equals só porque são objetos, não necessariamente garante-nos que estes objetos serão comparados de forma satisfatória ou semanticamente coerente... O que determina isso é se a classe dos objetos (Na verdade, a classe do objeto
left-most) comparado sobrescreve ou não o método
equals, definido na classe
Object.
Suponha a seguinte classe:
class UmaClasse{
private int x;
public UmaClasse(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
Se executarmos o seguinte código:
UmaClasse
umaClasse1 = new UmaClasse(10),
umaClasse2 = new UmaClasse(10)
;
System.out.println(umaClasse1.equals(umaClasse2));
O resultado no console será
Como a classe
UmaClasse não sobrescreve o método
equals da classe
Object, é exatamente este
equals da classe
Object que é executado. E você sabe o que é que está "escrito" dentro do equals da classe
Object? Não? Olhe só:
package java.lang;
public class Object{
//...
public boolean equals(Object obj) {
return (this == obj);
}
//...
}
A implementação dada pela classe
Object ao método
equals é exatamente a mesma coisa que se você fizesse uma comparação entre
umaClasse1 e
umaClasse2 utilizando o operador == !!! Logo, o
equals não necessariamente terá um efeito diferente do ==... Isso vai depender se a classe do objeto que invoca o
equals sobrescreve ou não este método.
Eu costumo dizer que utilizamos o operador == para verificarmos se dois objetos são
iguais, se dois objetos são, na verdade,
um mesmo objeto. E utilizamos o método
equals para verificar se dois objetos são
equivalentes.
Perceba que o
critério que determina se dois objetos são equivalentes ou não é arbitrário. Depende única e exclusivamente da implementação que
você dá ao método
equals. Por exemplo, vamos estabelecer que o critério para que um dado objeto
obj seja equivalente a um objeto do tipo
UmaClasse deva atender aos seguintes requisitos:
:arrow:
obj deve ser não-nulo
:arrow:
obj deve ser um objeto do tipo
UmaClasse ou compatível
:arrow:
obj - sendo ele um objeto do tipo
UmaClasse - deve ter o valor do campo
x igual ao valor do mesmo campo do objeto
UmaClasse que está invocando o método
equals.
Para que os objetos da classe
UmaClasse atendam a este critério de equivalência, esta classe deve sobrescrever o método
equals da seguinte forma:
class UmaClasse{
private int x;
public UmaClasse(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public boolean equals(Object obj) {
if(obj == null)
return false;
if(!(obj instanceof UmaClasse))
return false;
UmaClasse other = (UmaClasse)obj;
return this.x == other.x;
}
}
Agora sim! Se executarmos novamente aquele código que comparava, através do
equals, dois objetos do tipo
UmaClasse, teremos no console o resultado
Mas, como eu disse antes, fomos
nós quem determinamos o critério que determina se um objeto do tipo
UmaClasse é equivalente ou não a um outro objeto do tipo
Object... Nós poderiamos fazer qualquer tipo de estripulia na implementação do
equals :twisted:
Só de brincadeira: Vamos supor que, por algum motivo do além, os critérios que determinam se um objeto
obj qualquer é equivalente a um objeto do tipo
UmaClasse sejam os seguintes:
:arrow:
obj deve ser não-nulo
:arrow:
obj deve ser um objeto do tipo
UmaClasse ou compatível
:arrow:
obj - sendo ele um objeto do tipo
UmaClasse - deve ter seu campo
x igual ao dobro do campo
x do objeto
UmaClasse que está invocando o método
equals
Essa doideria ficaria assim:
class UmaClasse{
private int x;
public UmaClasse(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public boolean equals(Object obj) {
if(obj == null)
return false;
if(!(obj instanceof UmaClasse))
return false;
UmaClasse other = (UmaClasse)obj;
return 2*this.x == other.x;
}
}
Neste caso, se executarmos estas linhas:
UmaClasse
umaClasse1 = new UmaClasse(10),
umaClasse2 = new UmaClasse(10),
umaClasse3 = new UmaClasse(20)
;
System.out.println(umaClasse1.equals(umaClasse2));
System.out.println(umaClasse1.equals(umaClasse3));
Teremos a seguinte saída no console:
Mais um pouco de brincadeira? Ok: Seguem os seguintes critérios agora:
:arrow:
obj deve ser não-nulo
:arrow:
obj deve ser um objeto do tipo
UmaClasse,
Integer ou compatível com um destes.
:arrow: Se
obj é um objeto do tipo
UmaClasse, seu campo
x deve ter valor igual ao campo
x do objeto que invocou o
equals.
:arrow: Se
obj é um objeto do tipo
Integer, deve ter valor igual ao valor do campo
x do objeto
UmaClasse que invocou o
equals
Essa coisa esdrúxula ficaria assim:
class UmaClasse{
private int x;
public UmaClasse(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public boolean equals(Object obj) {
if(obj == null)
return false;
if(obj instanceof UmaClasse) {
UmaClasse other = (UmaClasse)obj;
return this.x == other.x;
}
if(obj instanceof Integer) {
Integer i = (Integer)obj;
return this.x == i.intValue();
}
return false;
}
}
Executem o seguinte código:
UmaClasse
umaClasse1 = new UmaClasse(10),
umaClasse2 = new UmaClasse(10)
;
System.out.println(umaClasse1.equals(umaClasse2));
System.out.println(umaClasse1.equals(new Integer(10)));
E terão a saída
Toda essa palhaçada foi só pra fixar o seguinte: É a
implementação do método equals que determina o critério de equivalencia entre dois objetos. Tudo depende do que está escrito lá dentro, ou seja, depende apenas do que
você põe lá dentro do
equals.
Recomento enfaticamente a leitura deste livro:
http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/[telefone removido]/sr=8-1/qid=[telefone removido]/ref=pd_bbs_sr_1/102-7559920-2532931?ie=UTF8&s=books
Este livro maravilhoso traz, entre outros tópicos importantissimos, uma análise do uso e implementação do método equals.
Divirtam-se!