Por que uma classe Java deve implementar comparável?
136
Por que o Java é Comparableusado? Por que alguém implementariaComparable em uma classe? Qual é um exemplo da vida real em que você precisa implementar comparáveis?
Aqui está uma amostra da vida real. Observe que Stringtambém implementa Comparable.
classAuthorimplementsComparable<Author>{String firstName;String lastName;@Overridepublicint compareTo(Author other){// compareTo should return < 0 if this is supposed to be// less than other, > 0 if this is supposed to be greater than // other and 0 if they are supposed to be equalint last =this.lastName.compareTo(other.lastName);return last ==0?this.firstName.compareTo(other.firstName): last;}}
mais tarde..
/**
* List the authors. Sort them by name so it will look good.
*/publicList<Author> listAuthors(){List<Author> authors = readAuthorsFromFileOrSomething();Collections.sort(authors);return authors;}/**
* List unique authors. Sort them by name so it will look good.
*/publicSortedSet<Author> listUniqueAuthors(){List<Author> authors = readAuthorsFromFileOrSomething();returnnewTreeSet<Author>(authors);}
Eu só quero observar que muitas vezes você deseja substituir equals(e, portanto hashCode) ser consistente com seu compareTométodo. Por exemplo, isso é necessário se você quiser que a turma seja agradável com a TreeSet.
Pidge
Por que não simplesmente voltar last?
Anirban Nag 'tintinmj'
@ AnirbanNag'tintinmj 'para classificar automaticamente pelo primeiro nome, caso o sobrenome seja o mesmo.
OddDev 5/08/15
Mais uma pela boa explicação de por que compareTo retorna um int e o que isso significa. Mais útil.
James.garriss
1
@ user3932000: Certo, esse é o objetivo de todas as interfaces. Mas observe que "outros métodos Java" incluem métodos escritos pelo usuário! Na verdade, eu diria que a maioria das interfaces é consumida pelo código do usuário. Em bases de código maiores, "se" rapidamente se torna "outros"
Enno Shioji
40
Comparável define uma ordem natural. O que isso significa é que você o define quando um objeto deve ser considerado "menor que" ou "maior que".
Suponha que você tenha vários números inteiros e queira classificá-los. Isso é bem fácil, basta colocá-los em uma coleção ordenada, certo?
TreeSet<Integer> m =newTreeSet<Integer>();
m.add(1);
m.add(3);
m.add(2);for(Integer i : m)...// values will be sorted
Mas agora suponha que eu tenha algum objeto personalizado, em que a classificação faça sentido para mim, mas seja indefinida. Digamos, eu tenho dados representando distritos por CEP com densidade populacional e quero classificá-los por densidade:
Agora, a maneira mais fácil de classificá-las é defini-las com uma ordem natural implementando Comparable, o que significa que existe uma maneira padrão de definir esses objetos para serem solicitados .:
Observe que você pode fazer o equivalente definindo um comparador. A diferença é que o comparador define a lógica de pedidos fora do objeto . Talvez em um processo separado eu precise ordenar os mesmos objetos por CEP - nesse caso, a ordem não é necessariamente uma propriedade do objeto ou difere da ordem natural dos objetos. Você pode usar um comparador externo para definir uma ordem personalizada em números inteiros, por exemplo, classificando-os por seu valor alfabético.
Basicamente, a lógica de pedidos deve existir em algum lugar. Isso pode ser -
no próprio objeto, se for naturalmente comparável (estende Comparable -eg inteiros)
fornecido em um comparador externo, como no exemplo acima.
bom exemplo, mas deve ser em TreeSet<Integer>vez de TreeMap<Integer>, pois o último não existe, os TreeMaps são sempre <Key,Value>-pairs. Aliás, uma hipótese TreeMap<District, Object>só funcionaria se o Distrito implementasse o Comparable, certo? Ainda tentando entender isso
phil294
14
Citado do javadoc;
Essa interface impõe uma ordem total aos objetos de cada classe que a implementa. Essa ordem é chamada de ordem natural da classe e o método compareTo da classe é chamado de método de comparação natural.
As listas (e matrizes) de objetos que implementam essa interface podem ser classificadas automaticamente por Collections.sort (e Arrays.sort). Objetos que implementam essa interface podem ser usados como chaves em um mapa classificado ou como elementos em um conjunto classificado, sem a necessidade de especificar um comparador.
Eu diria que a frase após a que você colocou em negrito é tão (se não mais) importante.
Michael Borgwardt
8
O fato de uma classe implementar Comparablesignifica que você pode pegar dois objetos dessa classe e compará-los. Algumas classes, como determinadas coleções (função de classificação em uma coleção), que mantêm os objetos em ordem, dependem deles para serem comparáveis (para classificar, você precisa saber qual objeto é o "maior" e assim por diante).
A maioria dos exemplos acima mostra como reutilizar um objeto comparável existente na função compareTo. Se você deseja implementar seu próprio compareTo quando desejar comparar dois objetos da mesma classe, diga um objeto AirlineTicket que você gostaria de classificar por preço (menos é classificado primeiro), seguido pelo número de escala (novamente, menos é em primeiro lugar), você faria o seguinte:
classAirlineTicketimplementsComparable<Cost>{publicdouble cost;publicint stopovers;publicAirlineTicket(double cost,int stopovers){this.cost = cost;this.stopovers = stopovers ;}publicint compareTo(Cost o){if(this.cost != o.cost)returnDouble.compare(this.cost, o.cost);//sorting in ascending order. if(this.stopovers != o.stopovers)returnthis.stopovers - o.stopovers;//again, ascending but swap the two if you want descendingreturn0;}}
O que Fernando quer dizer é: se você armazenar "coisas" que implementam Comparable em uma classe de contêiner classificado, a classe de contêiner classificado pode ordenar automaticamente essas "coisas".
30512 Ian Durkan
2
Comparable é usado para comparar instâncias da sua classe. Podemos comparar instâncias de várias maneiras, e é por isso que precisamos implementar um método compareTopara saber como (atributos) queremos comparar instâncias.
Dog classe:
package test;import java.util.Arrays;publicclassMain{publicstaticvoid main(String[] args){Dog d1 =newDog("brutus");Dog d2 =newDog("medor");Dog d3 =newDog("ara");Dog[] dogs =newDog[3];
dogs[0]= d1;
dogs[1]= d2;
dogs[2]= d3;for(int i =0; i <3; i++){System.out.println(dogs[i].getName());}/**
* Output:
* brutus
* medor
* ara
*/Arrays.sort(dogs,Dog.NameComparator);for(int i =0; i <3; i++){System.out.println(dogs[i].getName());}/**
* Output:
* ara
* medor
* brutus
*/}}
Main classe:
package test;import java.util.Arrays;publicclassMain{publicstaticvoid main(String[] args){Dog d1 =newDog("brutus");Dog d2 =newDog("medor");Dog d3 =newDog("ara");Dog[] dogs =newDog[3];
dogs[0]= d1;
dogs[1]= d2;
dogs[2]= d3;for(int i =0; i <3; i++){System.out.println(dogs[i].getName());}/**
* Output:
* brutus
* medor
* ara
*/Arrays.sort(dogs,Dog.NameComparator);for(int i =0; i <3; i++){System.out.println(dogs[i].getName());}/**
* Output:
* ara
* medor
* brutus
*/}}
Aqui está um bom exemplo de como usar comparável em Java:
Quando você implementa Comparableinterface, você precisa implementar o método compareTo(). Você precisa comparar objetos, para usar, por exemplo, o método de classificação da ArrayListclasse. Você precisa de uma maneira de comparar seus objetos para poder classificá-los. Portanto, você precisa de um compareTo()método personalizado em sua classe para poder usá-lo com o ArrayListmétodo de classificação. O compareTo()método retorna -1,0,1.
Acabei de ler um capítulo correspondente no Java Head 2.0, ainda estou aprendendo.
OK, mas por que não apenas definir um compareTo()método sem implementar uma interface comparável. Por exemplo, uma classe Citydefinida pela sua namee temperaturee
Respostas:
Aqui está uma amostra da vida real. Observe que
String
também implementaComparable
.mais tarde..
fonte
equals
(e, portantohashCode
) ser consistente com seucompareTo
método. Por exemplo, isso é necessário se você quiser que a turma seja agradável com aTreeSet
.last
?Comparável define uma ordem natural. O que isso significa é que você o define quando um objeto deve ser considerado "menor que" ou "maior que".
Suponha que você tenha vários números inteiros e queira classificá-los. Isso é bem fácil, basta colocá-los em uma coleção ordenada, certo?
Mas agora suponha que eu tenha algum objeto personalizado, em que a classificação faça sentido para mim, mas seja indefinida. Digamos, eu tenho dados representando distritos por CEP com densidade populacional e quero classificá-los por densidade:
Agora, a maneira mais fácil de classificá-las é defini-las com uma ordem natural implementando Comparable, o que significa que existe uma maneira padrão de definir esses objetos para serem solicitados .:
Observe que você pode fazer o equivalente definindo um comparador. A diferença é que o comparador define a lógica de pedidos fora do objeto . Talvez em um processo separado eu precise ordenar os mesmos objetos por CEP - nesse caso, a ordem não é necessariamente uma propriedade do objeto ou difere da ordem natural dos objetos. Você pode usar um comparador externo para definir uma ordem personalizada em números inteiros, por exemplo, classificando-os por seu valor alfabético.
Basicamente, a lógica de pedidos deve existir em algum lugar. Isso pode ser -
no próprio objeto, se for naturalmente comparável (estende Comparable -eg inteiros)
fornecido em um comparador externo, como no exemplo acima.
fonte
TreeSet<Integer>
vez deTreeMap<Integer>
, pois o último não existe, os TreeMaps são sempre<Key,Value>
-pairs. Aliás, uma hipóteseTreeMap<District, Object>
só funcionaria se o Distrito implementasse o Comparable, certo? Ainda tentando entender issoCitado do javadoc;
Edit: ..e deixou o importante em negrito.
fonte
O fato de uma classe implementar
Comparable
significa que você pode pegar dois objetos dessa classe e compará-los. Algumas classes, como determinadas coleções (função de classificação em uma coleção), que mantêm os objetos em ordem, dependem deles para serem comparáveis (para classificar, você precisa saber qual objeto é o "maior" e assim por diante).fonte
A maioria dos exemplos acima mostra como reutilizar um objeto comparável existente na função compareTo. Se você deseja implementar seu próprio compareTo quando desejar comparar dois objetos da mesma classe, diga um objeto AirlineTicket que você gostaria de classificar por preço (menos é classificado primeiro), seguido pelo número de escala (novamente, menos é em primeiro lugar), você faria o seguinte:
fonte
Uma maneira fácil de implementar várias comparações de campo é com o ComparisonChain da Guava - então você pode dizer
ao invés de
fonte
Por exemplo, quando você deseja ter uma coleção ou mapa classificado
fonte
Comparable é usado para comparar instâncias da sua classe. Podemos comparar instâncias de várias maneiras, e é por isso que precisamos implementar um método
compareTo
para saber como (atributos) queremos comparar instâncias.Dog
classe:Main
classe:Aqui está um bom exemplo de como usar comparável em Java:
http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2
fonte
Quando você implementa
Comparable
interface, você precisa implementar o métodocompareTo()
. Você precisa comparar objetos, para usar, por exemplo, o método de classificação daArrayList
classe. Você precisa de uma maneira de comparar seus objetos para poder classificá-los. Portanto, você precisa de umcompareTo()
método personalizado em sua classe para poder usá-lo com oArrayList
método de classificação. OcompareTo()
método retorna -1,0,1.Acabei de ler um capítulo correspondente no Java Head 2.0, ainda estou aprendendo.
fonte
OK, mas por que não apenas definir um
compareTo()
método sem implementar uma interface comparável. Por exemplo, uma classeCity
definida pela suaname
etemperature
efonte