comparator  XML
Índice dos Fóruns » Java Básico
Autor Mensagem
LPJava
GUJ Hacker

Membro desde: 18/04/2006 12:50:23
Mensagens: 5524
Localização: Bahia/Porto Alegre
Offline

ae pessoal ja abrir um topico uma vez sobre essa interface e ja fiz buscas aqui no guj.. li mais nao conseguir ainda entender a essencia dessa classe.nem como implementa-la de forma bem simples e funcional... fiz com a interface comparable e me dei ate bem.. veja...

mas com comparator as coisas nao anda nao.. quem puder me dar um help novamente ai.. agradeco!! mesmo..
e pq esse nao compila

Sun Certified Java Programmer 5.0
Blog:http://www.camilolopes.com
Twitter:www.twitter.com/camilolope
Linkedin: http://br.linkedin.com/in/camilolopes
Curso online OCPJP: http://pro.imasters.com.br/online/cursos/preparatorio-para-certificacao-java-ocjp
Autor livro Guia SCJP & JEE c/ Frameworks: http://blog.camilolopes.com.br/livrosrevistaspalestras/
[WWW]
lenando
Debugger
[Avatar]

Membro desde: 12/05/2006 01:09:44
Mensagens: 72
Localização: Blumenau/SC Brasil
Offline

Vc implementará a interface Comparator separadamenteo, para poder passar essa classe ao método sort(obj, ClasseImplComparator).

Acredito que a essência das interfaces Comparable e Comparator sejam idênticas, porém usando o Comparator, vc não precisará alterar a classe, como teria que fazer se usasse o Comparable. A classe que implementa Comparator é criada separadamente.

Acredito que a implementação deve ser idêntica para Comparable e Comparator, pois ambas tem a mesma lógica.

Desculpe-me a confusão ... para mim esse assunto é relativamente novo.

Att.
Fernando.

"Não existe ninguém tão sábio que não tenha nada para aprender e ninguém tão ignorante que não tenha nada para ensinar"
#@®®¡$
Moderador
[Avatar]

Membro desde: 13/02/2004 09:42:28
Mensagens: 807
Localização: São Paulo
Offline

Você usa Comparable quando quer implementar a comparação internamente aos objetos, e usa Comparator quando quer implementar a comparação de forma externa.

Exemplo:



Cada figura implementa Comparable e a primeira ordenação ordena as figuras de acordo com a área de cada uma. A segunda ordenação ordena as figuras de acordo com a área também, exceto se uma delas for um triângulo, daí ele considera a área com mais 20% (não, não faz sentido. Pra falar a verdade, acho que nem funciona direito, pois eu não estou considerando a hipótese de figura2 ser um triângulo).

Você também poderia, neste meu exemplo, não implementar Comparable em cada figura e criar um Comparator que simplesmente compare a área. Isso seria legal porque não iria duplicar o código de comparar a área em cada classe que implementa FiguraGeometrica.

Wilerson "#@®®¡$" de Oliveira
http://mundoestranho.net/blog/
Douglas Adams wrote:I love deadlines. I like the whooshing sound they make as they fly by.
[WWW] [ICQ]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

Estou partindo do pressuposto que você saiba trabalhar minimamente com generics, ok?
Bom, existem duas interfaces nessa brincadeira: A Comparable e a Comparator. Ambas têm o propósito de estabelecer uma relação de ordenação entre objetos. Por exemplo: Vamos supor que você cria um uma classe Quadrado

Esta é uma classe bem simples, só pra representar um quadrado mesmo. Essa classe disponibiliza um mecanismo que nos permite verificar se dois objetos do tipo Quadrado são equivalentes ou não: O método equals.
Vamos supor agora que queremos agora estabelecer uma ordenação entre quadrados. Digamos que nosso critério seja o seguinte:
Um quadrado q1 é maior que um quadrado q2, se a aresta de q1 for maior que a aresta de q2.
Um quadrado q1 é menor que um quadrado q2, se a aresta de q1 for menor que a aresta de q2.
Um quadrado q1 é igual a um quadrado q2, se a aresta de q1 for igual a aresta de q2.
Mas... essa classe por acaso disponibiliza algum mecanismo que nos permita descobrir se um determinado objeto Quadrado é maior ou menor que um outro objeto Quadrado? A resposta é não. Para podermos verificar se um quadrado é maior ou menor que o outro, segundo o critério mencionado acima, nós mesmos teriamos que fazer algum algoritmozinho pra determinar quando um Quadrado é menor ou maior que outro:

Este programa pega um punhado de objetos do tipo Quadrado e compara-os entre si, exibindo na tela a conclusão das comparações. A saída fica assim:

Perceba que neste caso, a comparação entre dois objetos Quadrado é feita fora da classe Quadrado. Esta comparação que fizemos não é uma comparação natural de um objeto Quadrado, ou seja, um objeto do tipo Quadrado não sabe olhar para outro Quadrado e dizer se ele próprio é maior, menor ou igual ao Quadrado para o qual ele está olhando...
Isso é meio chato, por que não teremos nunca como garantir um critério padrão para comparar objetos Quadrado. Digo isso pelo seguinte: Os critérios que utilizamos acima, fomos nós que definimos. Nada impede de um Joselito maluco da vida estabelecer um outro algoritmo, com um critério totalmente diferente do nosso para estipular quem é maior, menor ou igual a quem. O legal mesmo seria a própria classe Quadrado estabelecer o critério de comparação entre seus objetos. Nada mais justo, não é mesmo?
E de que forma podemos fazer isto? Bom, podemos seguir nossa intuiçao e colocar um método lá dentro da classe Quadrado com esse propósito. Que tal um método chamado, por exemplo, compararCom? O nome é bem intuitivo, né mesmo? Ok, mas agora vamos pensar em como esse método vai funcionar, para que possamos definir sua assinatura. A idéia doe colocarmos o método compararCom na classe Quadrado é permitir que um objeto desta classeQuadrado(q1, por exemplo) possa se auto-comparar com outro objeto do tipo Quadrado(q2). Isso nos leva a imaginar que queremos poder fazer algo assim com o q1:

Beleza! Creio que já temos então a assinatura do nosso método:

Mas... e que diabos esse método vai retornar??? Bom, o retorno desse método tem que ser alguma informação que nos diga de forma clara se q1 é maior, menor ou igual a q2. Que tal se o método sempre retornar um int? O valor desse int retornado seguiria a seguinte regrinha:
Se o q1(O objeto que invoca o compararCom) for maior que q2(O objeto passado por parâmetro para o compararCom), o int retornado será um inteiro extritamente negativo(<0) qualquer.
Se o q1 for maior que q2, o int retornado será um inteiro estritamente positivo(>0) qualquer.
Se o q1 for igual à q2, o int retornado será o inteiro zero.
Legal! O nosso método já tem um cabeçalho completo!

Agora, vamos tentar adicionar esse método à nossa classe Quadrado:

Na linha 31 aparece nosso novo método!!! Veja como ficou simples a implementação dele: Se a aresta do objeto que invocou o compararCom(representado pelo this) for maior que a aresta do objeto passado por parâmetro(representado por outro), então isso quer dizer que o objeto que invocou é maior que o objeto passado por parâmetro. Neste caso, o método deveria retornar um inteiro positivo, e é exatamente isso que ele faz! Como a aresta do this é maior que a aresta do outro, a primeira menos a segunda dá um valor positivo. E assim por diante.
Note também que alteramos o método equals, mais precisamente a linha 33. Estamos atrelando o resultado do equals com o resultado do compararCom. Fazemos isso porque parece ser extremamente consistente o equals retornar true quando o compararCom retornar 0, e vice-versa, uma vez que esses dois casos trazem a mesma semântica (significado).
Agora, em qualquer lugar do mundo em que nossa classe Quadrado for utilizada, os programadores poderão utilizar o método compararCom para conseguir obter uma ordenação natural de objetos do tipo Quadrado. Basta eles utilizarem assim nossa classe:

Basicamente, o que mudou foram as linhas 16 e 19. Ao invez de compararmos os resultados dos getAresta de cada objeto, utilizamos o resultado do compararCom para determinarmos se quadrados[quad] é maior, menor ou igual a quadrados[cmp]. Pouca coisa de vantagem? parece que sim, mas não é bem por aí... Parece que a vantagem é pequena porque o critério de comparação utilizado por Quadrado é relativamente simples. Imagine se tivessemos uma classe cujo critério de comparação dependesse de... hmm... 5 de seus 10 campos...
Outro ponto a favor, é que o critério em si, bem como sua implementação, ficam encapsulados dentro da classe, transparentes a quem vai utilizar a classe Quadrado.
Ok! Nossa classe agora tem um mecanismo próprio para estabelecer uma ordenação natural entre seus objetos. Legal! Mas se você acha que acabamos de inventar uma coisa nova, está redondamente enganado... Esse conceito de classes que definel uma ordenação natural para seus objetos vem deeeesde o Java 1.2. Tanto é, que existem classes da API Java que tiram proveito de objetos cujas classes determinam uma ordenação natural. Algumas classes e interfaces da API Java utilizam objetos desse tipo para criar conjuntos ordenados. Há também classes que têm métodos próprios para ordenar arrays e listas de objetos com base na ordenação natural destes.
Mas cabe aqui uma pergunta: Se toda essa infra-estrutura existe desde o Java 1.2 (bem velhinho...), como é que essas classes do Java mencionadas acima, que são mais velhas que a nossa classe Quadrado, vão advinhar que na nossa classe o método que faz a comparação chama-se compararCom, recebe um parâmetro do tipo Quadrado e retorna um int??? Simples: Elas não vão advinhar nada...
Mas então, como podemos "conectar" nossa classe Quadrado com essas classes do Java?
Estas classes da API Java que utilizam objetos auto-comparáveis estabelecem uma regrinha para a classe dos objetos que elas manipulam: A classe deve implementar a interface Comparable(java.lang.Comparable). Vamos pegar um exemplo: A classe TreeSet(java.util.TreeSet) implementa um conjunto de objetos que estão sempre ordenados. É como se fosse uma lista de objetos, que sempre está ordenada, e não tem objetos repetidos(objetos iguais). Sempre que você adiciona um objeto dentro de um TreeSet, esse TreeSet vai verificar se a classe do objeto que você inseriu determina uma ordenação natural. De que forma ele faz isso? Simples: verficando se a classe deste objeto dá um implements da interface Comparable! Veja o seguinte exemplo:

Neste código, estamos criando uma instância de TreeSet<Quadrado>, que armazenará ordenadamente os elementos do vetor de Quadrado quadrados. Intuitivamente, bastaria adicionar os objetos Quadrado em setQuadrados e pronto! Teríamos um conjunto de quadrados ordenado e sem repetições. Porém, há um pequeno problema: A classe TreeSet não tem como advinhar que a classe Quadrado estabelece uma ordenação natural... A classe Quadrado teria que "dar uma dica" disso pra classe TreeSet... Se executarmos o código acima, teremos uma saída mais ou menos assim:

Uma exceção lançada pela classe TreeSet!!! Mas por quê? Porque como a classe TreeSet esperava que a classe do objeto inserido (Quadrado) implementasse a interface Comparable! A classe TreeSet confiava que a classe Quadrado implementasse a interface Comparable. Mas nós traímos tal confiança... Em resposta, somos punidos com o lançamento de uma ClassCastException. Isso acontece porque, internamente, ao ser inserido um elemento (que não o primeiro do TreeSet), o TreeSet vai querer comparar o elemento sendo inserido com os elementos já existentes na lista. Pra isso, ele vai tentar fazer um cast mais ou menos assim:

Notou como a classe TreeSet "confia" que o objeto inserido é de uma classe que implementa Comparable? Ela vai lá e faz o cast direto. Bom, como a nossa classe Quadrado não implementa Comparable, a instrução acima conhecidamente lança uma ClassCastException.
Bom, agora sabemos que as classes da API java que utilizam algum mecanismo de comparação de outros objetos, geralmente exigem que esses objetos sejam objetos Comparable.
Mas aí cabe uma pergunta: De que adianta a nossa classe implementar Comparable? Por acaso isso vai fazer alguma mágica capaz de dar poderes de advinhação ao, por exemplo, TreeSet, permitindo que ele "descubra" qual é o método que faz a comparação?
Resposta: Quase isso... Na verdade, a interface Comparable<T> declara um método com a seguinte assinatura:

Familiar essa assinatura, não?
O contrato (A grosso modo: regras de uso. Procurem ler a respeito de "design by contract") do método compareTo, em linhas gerais, estabelece que a implementação deste método deve estabelecer uma ordenação aos objetos da classe que dá implements em Comparable. Partindo do pressuposto que uma classe que implementa uma interface, obrigatoriamente implementa seus métodos, e partindo também do pressuposto que o contrato dos métodos implementados foi "honrado", um TreeSet<T> faz algo parecido com isso:

É dessa forma que o TreeSet faz a comparação: Como ele assume que os elementos são objetos de classes que dão implements em Comparable, nada mais justo de admitir, por conseqüência, que estes objetos podem ser convertido para Comparable e utilizar então o método compareTo desta interface.
Essa é a "dica" que a classe Quadrado deve dar para que, não só as classes da API Java mencionadas antes, mas também para todos nós programadores, de que seus objetos têm uma ordenação natural: implements Comparable!!!
Façamos a seguinte alteração na classe Quadrado:

Alteramos agora a linha 1 para declarar que a nossa classe implementa a interface Comparable<Quadrado>. Na linha 31, trocamos nosso método compararCom por uma implementação do método compareTo, previsto na interface Comparable (Na verdade trocamos apenas os nomes dos métodos... ).
Agora sim, se rodarmos novamente aquela classe TesteTreeSet, vai funcionar direitinho, dando a seguinte saída:

Temos aí a listagem dos punhado de quadrados que tinhamos, e depois uma listagem do conjunto ordenado de quadrados, implementado pelo TreeSet.
Um outro exemplo de classe do Java que utiliza objetos Comparable, é a classe Arrays(java.util.Arrays). Ela é uma classe utilitária que tem vários métodos estáticos para auxiliar a manipulação de vetores. Um destes métodos é o sort, utilizado para ordenar um vetor. Uma das suas várias assinaturas é esta:

Esta sobrecarga de sort exige que os elementos do vetor passado por parâmetro seja de uma classe que implemente a interface Comparable, senão ele vai dar o mesmo problema que vimos com o TreeSet...
Rodem o seguinte programa:

O resultado esperedo é o seguinte:

Veja que o vetor quadrados foi alterado de forma a ter todos seus elementos postos em ordem, segundo os critérios implementados pelo método compareTo da classe Quadrado.
Mais uma coisa a se notar: Percebeu que as vezes chamamos um "objeto de classe a qual implementa Comparable" simplesmente de "objeto Comparable"? Isto traz uma carga semântica muito importante! "Comparable" é igual a "comparável" em inglês. Então, um objeto de uma classe a qual implementa a interface Comparable, é um objeto que pode ser comparado.
Já a interface Comparator, tem também o propósito de estabelecer a ordenação entre objetos, mas de uma forma um pouco diferente...
Imagine a seguinte classe:

Ok! Até aqui, nada de novo. Mas e se quisermos estabelecer um outro critério de ordenação para os objetos Cliente? Por exemplo, como faríamos para ter um vetor de objetos Cliente, ordenado não pelo cpf, mas pelo nome?
Inicialmente, podemos simplesmente, no meio do nosso código, implementar algum algoritimo de ordenação e ordenar o vetor utilizando o método getNome dos objetos no vetor. O primeiro ponto ruim disso é que vai melecar o seu código.
Mas aí podemos pensar em criar uma classe só pra fazer tal ordenação. Legal! Mas vamos ter que continuar a implementar algum algoritmo de ordenação... Estariamos re-inventando a roda, por que o Java já tem na classe Arrays métodos para ordenação de vetores. Mas como que o Arrays vai saber que não queremos utilizar o critério da ordenação natural (ordenar por cpf), e sim, um outro critério (ordenação por nome)? É aí que entra em jogo a interface Comparator(java.util.Comparator)!
Olhe só que interessante essa sobrecarga do método sort da classe Arrays:

Temos aí agora como parâmetro, além do vetor a ser ordenado, um objeto de uma classe a qual implemente a interface Comparator(um objeto Comparator). Qual é o papel da interface Comparator nesse método?
A interface Comparator<T> declara dois métodos:
public int compare(T, T)
public boolean equals(Object)
Para este post, esqueça esse método equals da interface. Apenas tenha em mente que este equals não diz respeito aos objetos que comparados. Este equals é para verificar se dois objetos Comparator são equivalentes. Trata-se de um uso avançado, que não abordaremos aqui.
O contrato do método compare é semelhante ao do compareTo da interface Comparable. A diferença é que, enquanto o compareTo serve para comparar o próprio objeto que invoca o compareTo (this) com o objeto passado por parâmetro (outro), o método compare da interface Comparable serve para comparar o objeto do tipo T passado no primiero parâmetro com o objeto do tipo T passado no segundo parâmetro.
A classe que implementar a interface Comparator<T>, terá que implementar o método compare, implementando nele algum critério de comparação entre objetos do tipo T, seja lá quem for T.
Isso é interessante para nós, pois temos aqui a chance de criar o tal vetor de clientes ordenado por nome. Podemos criar uma classe que implemente Comparator e escrever o método compare de tal forma, que estabeleça que
Um objeto Cliente c1 é menor que um objeto Cliente c2, se o nome de c1 for "alfabeticamente menor" que o nome de c2. Neste caso, compare deve retornar um número estritamente negativo.
Um objeto Cliente c1 é maior que um objeto Cliente c2, se o nome de c1 for "alfabeticamente maior" que o nome de c2. Neste caso, compare deve retornar um número estritamente positivo.
Um objeto Cliente c1 é igual a um objeto Cliente c2, se o nome de c1 for "alfabeticamente igual" ao nome de c2. Neste caso, compare deve retornar zero.

Vamos ver como ficaria esse Comparator:

Agora, vamos criar uma classe de teste que vai criar um vetor de clientes e imprimila 3 vezes: desordenada, ordenada por nome e ordenada naturalmente (por cpf):

Na linha 23, estamos ordenando o vetor clientes com o sort que usa um Comparator para realizar a ordenação. Internamente, sempre que ele precisar comparar alguma elemento e1 com algum outro elemento e2 do vetor, ele vai fazer algo parecido com isto:

A saída deste programa deve ser a seguinte:

Um outro uso é criar uma classe que implemente Comparator para estabelecer uma ordenação entre objetos de uma classe a qual não define uma ordenação natural (não implementa Comparable).
A classe TreeSet tem também um contrutor que recebe um objeto Comparator por parâmetro. É uma boa saída para criar conjuntos do objetos não-comparáveis naturalmente. Só fique atento para o seguinte: Nesses casos, nem sempre é fácil ou mesmo possível manter uma consistência entre os métodos equals e o compare. Você deve analisar qual o possível impacto que isso possa ter no seu programa.

Bom, Acho que é isso.
Qualquer dúvida ou correção, postem mais.
Valeu!

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
Ironlynx
Moderador
[Avatar]

Membro desde: 02/05/2003 01:06:41
Mensagens: 3515
Localização: The other side of the screen
Offline

Mantu, seus tópicos dariam um livro da mais alta qualidade!
Pq vc não pega alguns deles e transforma em tutoriais aqui para o GUJ?

Não basta persistir...tem que prevalecer!
Ironlynx
Anarquista de Sistemas
http://osereojava.blogspot.com/
[WWW]
thiagotbo
Thread.start()
[Avatar]

Membro desde: 07/02/2007 14:11:46
Mensagens: 49
Localização: Uberlândia - MG
Offline

Isso é que é qualidade GUJ de resposta!

Como o Ironlynx disse Mantu, seus tópicos dariam tutoriais excelentes !

Continue assim hehe... pq tah me ajudando pra karamba... hehe !! !! !!

Thiago Borges de Oliveira.

Qto mais aprendo, mas ignorante me sinto...
[Yahoo!] [MSN]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

Ironlynx wrote:Mantu, seus tópicos dariam um livro da mais alta qualidade!
Pq vc não pega alguns deles e transforma em tutoriais aqui para o GUJ?

Eu já enviei um uma vez, mas não tive resposta. Talvez tenha ficado aquém do esperado de um tutoria do guj, hehehe...
Obrigado pela força, pessoal!

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
omaisnormalbaba
JavaGuru

Membro desde: 27/03/2006 18:45:11
Mensagens: 223
Localização: Passos - Mg
Offline

Bom dia.. Porque que quando eu chamo:


o metodo getIdade() é da instancia int idade;
Ele diz esse erro:

um tipo int nao pode ser derreferenciado?

omaisnormalbaba!!!!!!!!!!!!
[Email] [MSN]
 
Índice dos Fóruns » Java Básico
Ir para:   
Powered by JForum 2.1.8 © JForum Team