【发布时间】:2011-04-12 17:09:21
【问题描述】:
为什么使用 Java Comparable?为什么有人会在课堂上实现Comparable?什么是您需要实现可比较的现实生活示例?
【问题讨论】:
-
这里有一个很好的例子:java67.blogspot.com/2012/10/…
标签: java
为什么使用 Java Comparable?为什么有人会在课堂上实现Comparable?什么是您需要实现可比较的现实生活示例?
【问题讨论】:
标签: java
这是一个真实的示例。注意String 也实现了Comparable。
class Author implements Comparable<Author>{
String firstName;
String lastName;
@Override
public int 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 equal
int last = this.lastName.compareTo(other.lastName);
return last == 0 ? this.firstName.compareTo(other.firstName) : last;
}
}
稍后..
/**
* List the authors. Sort them by name so it will look good.
*/
public List<Author> listAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
Collections.sort(authors);
return authors;
}
/**
* List unique authors. Sort them by name so it will look good.
*/
public SortedSet<Author> listUniqueAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
return new TreeSet<Author>(authors);
}
【讨论】:
equals(因此是hashCode)以与您的compareTo 方法保持一致。例如,如果您希望班级与TreeSet 一起玩,这是必要的。
last?
Comparable 定义了自然排序。这意味着当一个对象应该被认为是“小于”或“大于”时,您正在定义它。
假设你有一堆整数,你想对它们进行排序。这很简单,只需将它们放在一个排序的集合中,对吗?
TreeSet<Integer> m = new TreeSet<Integer>();
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted
但现在假设我有一些自定义对象,排序对我来说是有意义的,但未定义。假设我有按邮政编码和人口密度表示地区的数据,我想按密度对它们进行排序:
public class District {
String zipcode;
Double populationDensity;
}
现在对它们进行排序的最简单方法是通过实现 Comparable 以自然排序来定义它们,这意味着这些对象被定义为排序的标准方式。:
public class District implements Comparable<District>{
String zipcode;
Double populationDensity;
public int compareTo(District other)
{
return populationDensity.compareTo(other.populationDensity);
}
}
请注意,您可以通过定义比较器来做同样的事情。不同之处在于比较器定义了对象之外的排序逻辑。也许在一个单独的过程中,我需要按邮政编码对相同的对象进行排序——在这种情况下,排序不一定是对象的属性,或者与对象的自然排序不同。您可以使用外部比较器来定义整数的自定义排序,例如按字母值对它们进行排序。
基本上,排序逻辑必须存在于某个地方。那可以-
在对象本身中,如果它是自然可比较的(扩展 Comparable - 例如整数)
在外部比较器中提供,如上例所示。
【讨论】:
TreeSet<Integer> 而不是TreeMap<Integer>,因为后者不存在,TreeMaps 总是<Key,Value>-pairs。顺便说一句,假设的 TreeMap<District, Object> 只有在 District 实施 Comparable 时才有效,对吧?仍在尝试理解这一点
引用自javadoc;
这个接口强加了一个总 对每个类的对象进行排序 实现它。这个排序是 称为类的自然 排序和类的 compareTo 方法被称为其自然 比较法。
对象的列表(和数组) 实现这个接口可以排序 自动由 Collections.sort (和 Arrays.sort)。 实现的对象 这个接口可以作为key 排序的地图或作为元素 排序集,无需 指定一个比较器。
编辑:..并将重要的部分加粗。
【讨论】:
类实现Comparable 的事实意味着您可以从该类中获取两个对象并进行比较。某些类,例如某些保持对象有序的集合(集合中的排序函数)依赖于它们的可比性(为了进行排序,您需要知道哪个对象是“最大的”等等)。
【讨论】:
上面的大多数示例都展示了如何在 compareTo 函数中重用现有的可比较对象。如果您想在比较同一类的两个对象时实现自己的 compareTo,比如说您想按价格排序的 AirlineTicket 对象(less 排在第一位),然后是中途停留的次数(同样,less 是排名第一),您将执行以下操作:
class AirlineTicket implements Comparable<Cost>
{
public double cost;
public int stopovers;
public AirlineTicket(double cost, int stopovers)
{
this.cost = cost; this.stopovers = stopovers ;
}
public int compareTo(Cost o)
{
if(this.cost != o.cost)
return Double.compare(this.cost, o.cost); //sorting in ascending order.
if(this.stopovers != o.stopovers)
return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
return 0;
}
}
【讨论】:
Cost 有一个属性cost 作为AirlineTicket?属性stopovers(在两个类中)也一样吗?很奇怪…… Cost 的实现是什么?
实现多字段比较的一种简单方法是使用Guava's ComparisonChain - 然后你可以说
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(lastName, that.lastName)
.compare(firstName, that.firstName)
.compare(zipCode, that.zipCode)
.result();
}
而不是
public int compareTo(Person other) {
int cmp = lastName.compareTo(other.lastName);
if (cmp != 0) {
return cmp;
}
cmp = firstName.compareTo(other.firstName);
if (cmp != 0) {
return cmp;
}
return Integer.compare(zipCode, other.zipCode);
}
}
【讨论】:
Comparable 用于比较类的实例。我们可以通过多种方式比较实例,这就是为什么我们需要实现一个方法 compareTo 以便了解我们想要如何(属性)比较实例。
Dog类:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[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类:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[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
*/
}
}
这是一个如何在 Java 中使用可比性的好例子:
http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2
【讨论】:
例如当你想要一个排序的集合或map
【讨论】:
好的,但为什么不直接定义compareTo() 方法而不实现可比较的接口。
例如一个类City由它的name和temperature和
public int compareTo(City theOther)
{
if (this.temperature < theOther.temperature)
return -1;
else if (this.temperature > theOther.temperature)
return 1;
else
return 0;
}
【讨论】:
实现Comparable接口时,需要实现方法compareTo()。您需要它来比较对象,以便使用例如ArrayList 类的排序方法。您需要一种方法来比较您的对象以便能够对它们进行排序。所以你需要在你的类中自定义一个compareTo() 方法,这样你就可以将它与ArrayList 排序方法一起使用。 compareTo() 方法返回 -1,0,1。
我刚刚阅读了 Java Head 2.0 中的相应章节,我还在学习中。
【讨论】: