Como comparar objetos - Classe abstrata Comparable e o método compareTo

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.


Comparando objetos em Java

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.




A classe abstrata Comparable e o método compareTo()

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!

Exemplo de código - Comparando Objetos

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":

Carro.java

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

Exercício de Java

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.

2 comentários:

André de Souza disse...

agora o negocio ficou feio.
eu nao entendi.

eu entendi o porque de implementar o metodo compareto mas nao entendi como foi implementado...

o metodo recebe um objeto y e compara como um objeto x

objeto y = instancia da classe carro
e objeto x =???? variavel da instancia da classe carro... eu nao entendi

e o retorno do metodo compareto é usado onde???.... no arrays.sort?? nao entendi

Alex Amorim disse...

André de Souza , o retorno do método compareto foi feito no método sort da classe Arrays quando é chamado na classe main , como foi implementado na classe Carro a interface Comparable o método sort vai ordenar segundo foi implementando lá. já testou apagar o método compareto da classe Carro e rodar a main pra vê o que acontece ?

Dicas e Novidades de Java por e-mail

Sabe quanto custa um bom livro de java?
Entre R$ 100,00 e R$300,00

Sabe quanto custa um bom curso presencial de Java?
Entre R$ 1.500,00 até R$ 4.000,00

Sabe quanto custa estudar pelo Java Progressivo?
Absolutamente nada.

Porém, também precisamos de sua ajuda e apoio.
Para isso, basta curtir nossa Fan Page e clicar no botão G+ do Google.