Como comparar uma clase com xclasse

Note que estamos falando entre comparar se dois objetos são iguais ou não!

Para isso existe na linguagem Java dois métodos fundamentais chamados equals(...) e hashCode() que são declarados na classe java.lang.Object por padrão e são parte da biblioteca principal (core) do Java.

Você deve implementar esses dois métodos em suas classes que precisam ser comparadas!

O método equals() é usado para comparar se um objeto é igual o outro.

O método hashCode() é usado para gerar um número de identificação correspondente ao objeto.

Boa parte das classes padrões da linguagem Java usam esses métodos para poder inserir e capturar objetos em uma lista, também para evitar duplicidades de objetos como o caso do HashSet por exemplo.

A implementação padrão dentro do objeto java.lang.Object utiliza o método equals para comparar o endereço de memória entre os objetos, e o método retorna "true" se ambos objetos referenciam/apontam para o mesmo endereço de memória.

Mas a linguagem recomenda que esses métodos sejam re-escritos (Override) para que eles definam alguma forma lógica ou de negócio para comparar o objeto. Por exemplo a classe java.lang.String sobrescreve esses métodos para comparar o seu conteúdo, para retornar "true" se dois objetos possuem a mesma cadeia de caracteres.

Algumas regras são recomendadas na implementação

  • Reflexão: Objetos devem ser iguais a si mesmos; o.equals(o) == true

  • Simetria: Se o objeto "a" é igual ao o objeto "b" (a.equals(b)); Então "b" deve ser igual a "a".

  • Transição: Se a.equals(b) == true e b.equals(c) == true então c.equals(a) deve ser true.

  • Consistência: Várias chamadas consecutivas do método equals() deve sempre retornar o mesmo resultado enquanto nenhuma propriedade do objeto não for modificada.

  • Comparação com Null: A comparação com um objeto nulo (null) numca deve retornar NullPointerException e deve ser tratado como false; a.equals(null) == false

Contrato de relação entre equals() e hashCode()

  • Se dois objetos são iguais pelo método equals() então o resultado do método hashCode() deve ser o mesmo.

  • Se dois objetos não são iguais pelo método equals() então o resultado do hashCode() pode ser o mesmo ou não.

Passo-a-Passo para sobrescrever o método equals()

  1. Valide usando this, se iguais retorne true

  2. Valide se null, se nulo retorne false

  3. Valide se o objeto é do mesmo tipo usando instanceof, se não é, retorne false

  4. Tente fazer o cast do objeto

  5. Compare os atributos do objeto começando pelos valores numéricos. Se não forem iguais retorne false

OBS: Não confunda essa comparação com a comparação de grandeza dos valores de um objeto; se um valor é menor ou maior que o outro, por exemplo, nesse caso teríamos que abordar a implementação das interfaces Comparable e Comparator do Java.

Exemplo

import java.util.List; import java.util.ArrayList; public class Carro { private String modelo; private String cor; private int ano; public Carro(String modelo, String cor, int ano) { this.modelo = modelo; this.cor = cor; this.ano = ano; } @Override public boolean equals(Object o) { if(this == o) return true; if(o == null || getClass() != o.getClass()) return false; Carro c = (Carro) o; if(ano != c.ano) return false; if(!modelo.equals(c.modelo)) return false; return cor.equals(c.cor); } @Override public int hashCode() { int result = (modelo != null ? modelo.hashCode() : 0); result = 31 * result + (cor != null ? cor.hashCode() : 0); result = 31 * result + ano; return result; } @Override public String toString() { return modelo + "," + cor + "," + ano; } public static void main(String args) { List<Carro> listaCarros = new ArrayList<Carro>(); listaCarros.add(new Carro("Ford","Azul",2017)) listaCarros.add(new Carro("Honda","Preto",2016)) listaCarros.add(new Carro("Toyota","Branco",2015)) Carro meuCarro = new Carro("Honda","Preto",2016); for(Carro carro : listaCarros) { if(carro.equals(meuCarro)) { System.out.println("O Carro "+carro+" é iqual ao meu!"); } } } }

Referências

No tutorial passado de nossa apostila de Java, falamos sobre as Interfaces em Java, que fazem uso de diversos conceitos de Orientação a Objetos que estamos estudando, como Polimorfismo e Classes e Métodos Abstratos. Como de praxe, iremos ensinar mais uma lição de Java englobando diversos assuntos.

Hoje vamos aprender como comparar objetos (maior, menor, igual etc), e para isso faremos uso da classe abstrata Comparable e de seu método compareTo( ).

E para ver uma utilidade prática desses assuntos, vamos mostrar um exemplo através da ordenação de elementos de um Array.

  • Estudar offline pela apostila Java Progressivo

Como se compara uma coisa com outra? Analisamos uma característica que deve ser mensurável. Por exemplo, para comparar dois números, fazemos uso de seus valores. Mas poderíamos comparar o nome deles, através da ordem alfabética. Embora 1 seja maior que 2 na comparação de seus valores, "um" é maior que "dois", pois a letra "u" vem depois da letra "b". Ou seja, não faz sentido comparar duas coisas, e sim duas características específicas e mensuráveis. Por exemplo, não se compara banana com maçã. Mas podemos comparar o tanto de vitaminas em cada uma delas, ou seu peso, pois são características mensuráveis. E objetos? Como comparamos um objeto? Como comparo um objeto "secretário" com o objeto "gerente", ambos a classe "Funcionários" de uma empresa? Se tiver captado a ideia, verá que não dá pra se comparar assim. Mas podemos comparar uma características específica de cada objeto, como o salário de cada funcionário, ou a data de entrada na empresa ou seus números de identificação. Portanto, quem vai comparar é que escolhe como vai ser a comparação.

Existe uma classe especial em Java que é responsável por fazer comparações de objetos, que é a classe Comparable. Ela usada como padrão de comparação.


Por exemplo, vimos em nossos tutoriais sobre Arrays que existe um método chamado sort(), que ordena os elementos de um Array, do menor para o maior. Porém, como explicamos no tópico passado, não se compara coisas genéricas, como objetos, e sim coisas específicas, que podem ter seus valores medidos.

Ora, se não dá pra comparar, como a classe Comparable serve para comparar?

Se eu quiser comparar um carro com outro, através da classe Comparable, o que ela vai comparar, então?

A resposta está no tutorial passado, sobre classes e métodos abstratos: ela serve para comparar qualquer coisa, mas nada em específico.

Essa comparação é feita através do método compareTo(Object o), que recebe um objeto (se lembre que todos os objeto são derivados da classe Object, logo, todo e qualquer objeto que é possível criar em Java é derivado de Object).

Esse método retorna 3 números: -1, 0 ou 1. Vamos supor que temos um objeto "X" e queremos comparar com o objeto "Y".

Usamos esse método assim: X.compareTo(Y)

Caso "X" seja maior que "Y", o método retorna 1. Caso "X" seja menor que "Y", o método retorna -1. Caso "X" seja igual à "Y", o método retorna 0. Ok. Já sabemos que essa classe compara objetos, e que o método retorna o valor dessa comparação (-1, 0 ou 1). Mas O QUÊ e COMO essa classe e esse método comparam? Que característica do objeto? Ela não diz, pois não pode adivinhar o que raios você vai querer comparar. Então é você que vai escolher, que característica do objeto comparar. Ou seja, você vai implementar a comparação.

Implementar, isso te lembra algo? Sim, implements.


A classe Comparable está lá, com seu método compareTo(), declarados e prontos para serem usados. Mas a maneira que é feita essa comparação, você programador Java que decide. Vamos criar um exemplo para você ver melhor como as coisas funcionam!
Crie diversos objetos do tipo "Carro", onde eles tem um nome e um ano de fabricação.

Coloque esses carros em um Array, e usando o método sort, ordene esses objetos de modo a imprimir a lista de nomes e carros, ordenada por ano de fabricação do carro, do mais antigo para o mais novo.

Primeiramente, vamos criar a classe "Carro". Ela é bem simples, tem dois atributos: o "nome" do carro e seu "ano", bem como seus métodos getters. Porém, vamos querer comparar objetos dessa classe.

Logo, os objetos tem que se 'comparáveis' em Java, e para isso, basta fazer com que a classe "Carro" seja um implemento (implements) da interface "Comparable":

public class Carro implements Comparable{ }

Bom, mas essa classe abstrata tem o método compareTo, que recebe um objeto.

E como todo método de uma classe abstrata, esse método DEVE ser implementado! Como explicamos, ele tem que retornar um inteiro.

Se quiser usar ele junto com outras funcionalidades do Java, você deve fazer isso de modo que, ao comparar um objeto "X" com um método "Y", tenhamos que fazer: X.compareTo(Y)

E, como já havíamos dito, devemos fazer:
  • Caso "X" seja maior que "Y", o método retorna 1.
  • Caso "X" seja menor que "Y", o método retorna -1.
  • Caso "X" seja igual à "Y", o método retorna 0. 

Então vamos lá!

Como queremos comparar o ano dos carros, devemos comparar o atributo "ano". 

E para isso, basta usar o getter desse atributo.

A única diferença que temos nesse caso é que o método compareTo recebe um tipo bem genérico, o tipo Object.

Devemos fazer um casting, que é como se estivéssemos dizendo ao Java que objeto específico é esse Object, pois vamos usar o método getAno(), e o Object obviamente não tem esse método.

Vamos chamar esse Object recebido pelo método compareTo() de "o".

Vamos armazená-lo na variável "car" do tipo "Carro". O casting é feito assim:

Carro car = (Carro) o;

Pronto! Agora só devemos comparar os anos dos carros.

Na classe "Carro", vamos comparar o ano armazenado na variável "ano" com o ano do carro que recebemos por meio do objeto "o".

Aqui não tem segredo, simplesmente usamos os testes condicionais IF ELSE.

Como queremos comparar o objeto "X" com "Y" através de : X.compareTo(Y)

É fácil ver que dentro da classe, "getAno()" retorna o ano do objeto X, e vamos comparar com o ano do objeto Y, dado por Y.getAno()

Caso "getAno() > car.getAno()", é porque o ano de X é maior, e retornamos 1.

Caso "getAno() < car.getAno()", é porque o ano de Y é maior, e retornamos -1.

Caso contrário, os anos são iguais e retornamos 0.

Veja como fica o código da classe "Carro":

public class Carro implements Comparable{ private int ano=0; private String nome; public Carro(int ano, String nome){ this.ano = ano; this.nome = nome; } public int compareTo(Object o){ Carro car = (Carro) o; if(getAno() > car.getAno()){ return 1; }else{ if(getAno() < car.getAno()){ return -1; }else{ return 0; } } } public int getAno(){ return this.ano; } public String getNome(){ return this.nome; } }

Agora vamos criar nossa classe principal, que tem a main().

Nela, vamos criar um vetor de Carros, de nome "carros" e criar 4 carros nesse array:

um fusca, um gol, um fiat uno e uma hilux.

Em seguida, usamos o método sort que vai ordenar esses carros: Array.sort(carros)

Como implementamos a classe Carros para comparar o ano do carro, esse método vai ordenar os carros de acordo com o ano, do mais velho para o mais novo.

Depois, vamos printar cada elemento do carro usando o laço for para arrays, que vai exibir o nome e ano dos carros. Veja como ficou nossa classe principal:

classeComparable.java

import java.util.Arrays; public class classeComparable { public static void main(String[] args) { Carro[] carros = {new Carro(1974, "Fusca"), new Carro(2014, "Hilux"), new Carro(2000, "Uno"), new Carro(1998, "Gol")}; Arrays.sort(carros); for(Carro car : carros) System.out.println(car.getNome() + "\t" + car.getAno()); } }

Ao roda, o resultado é como esperávamos:

Fusca 1974

Gol         1998

Uno         2000

Hilux         2014

Crie uma classe "Funcionario", que recebe o cargo de cada funcionário bem como seu salário.

Crie um array com 5 objetos da classe "Funcionario" e em seguida os ordene com o método sort da classe Arrays, que vai ordenar os funcionários de acordo com o salário deles.

Exiba o nome e salário de cada um, e ao final o total que essa empresa gasta com esses funcionários em um ano.

Última postagem

Tag