欢迎来到it培训的黄埔军校——智游教育!

5 分钟搞定 java comparable 接口-永利国际

于2017-03-03 10:25:26 发表在java知识库

comparable接口时用来干什么的呢?


我们应该如何对事物进行比较和排序?这问题听上去有点莫名其妙,但我希望你认真考虑一下。比方说,我们有一组苹果:
例1

我们要怎样对它们进行排序呢?我们希望通过重量进行排序吗?如果是的话,排序是从最轻到最重还是从最重到最轻?当我们对它们进行排序的时候,我们需要反复比较两个苹果的重量,直到正确地排好所有的苹果。苹果1比苹果2重?那它比苹果3重吗?我们需要不断比较,直到完成排序。comparable接口可以帮助我们实现这一目标。comparable本身不能对对象进行排序,但接口定义的方法 int compareto(t)可以。


让我们通过使用compareto()方法来看看哪个苹果更重,开始吧。
例2

compareto()方法的工作原理是返回一个int值——或正,或负,或为零。它通过调用作为参数的对象来比较对象。负数表示调用的对象比参数“轻”。如果我们用大小来比较苹果,那么上面的调用会返回一个负数,例如-400,因为红苹果比青苹果小。如果两个苹果重量相等,那么调用将返回0。如果红苹果更重,那么compareto()将返回一个正数,例如68。


compareto()的灵活性

如果我们反复调用上面的compareto()方法,那么我们可以通过大小来排序,这很棒,但并非故事的结束。如果我们想通过颜色来给苹果排序呢?抑或是重量?我们也可以做到。关键是,我们的客户——让我们叫他胖子农夫(见例3),需要在我们开始开发之前精确定义需要如何对苹果进行排序。
例3
他可以通过回答这两个问题来做到这一点:
1.       他希望苹果如何进行排序?他希望我们比较什么特征?
2.       在那样的环境中,“小于”,“等于”和“大于”指的是什么意思?
也可以使用多个特征,这个后面我们会讲。


在第一个例子中,我们将通过重量对苹果排序。只需要一行代码。
 collections.sort(apples);
例4

上面的代码行可以为我们做到所有的排序工作,只要我们事先定义好如何对苹果进行排序(这就需要多行代码了)。
让我们开始写苹果类吧。

public class apple implements comparable {
    private string variety;
    private color color;
    private int weight;
    @override
    public int compareto(apple other) {
        if (this.weight < other.weight) {
            return -1;
        }
        if (this.weight == other.weight) {
            return 0;
        }
        return 1;
    }
}
例5


这是apple类的第一个版本。由于我们使用的是compareto方法,并且正在排序苹果,所以我实现了comparable接口。在这第一个版本中,我们通过重量比较对象。在我们的compareto()方法中,我们写一个if条件,说明如果这个苹果的重量小于其他的苹果,那么返回一个负数,为了保持简单,我们假定它为-1。请记住,这意味着这个苹果轻于apple ‘other’。在第二个if语句中,我们要说明,如果苹果重量相等,那么返回一个0。当然,如果这个苹果既不是更轻,又不是一样重,那就只能比其他苹果更重了。在这种情况下,我们返回一个正数,假定为1。

正如我前面提到的,我们还可以使用compareto()比较多个特征。比方说,我们第一通过品种排序苹果,但如果两个苹果是同一品种,那么我们就按颜色排序。最后,如果这两个特性相同,那么我们将按重量排序。虽然我们可以手动实现这件事,就像我在最后一个例子中做的那样,但是其实可以用一种简洁得多的方式实现。一般来说,最好是重用现有的代码,而不是自己写。我们可以在integer、string和枚举类中使用compareto方法来比较值。由于我们没有使用integer对象,用了int,所以我们不得不使用来自于integer包装器类的一个静态的helper方法来比较两个值。
public class apple implements comparable {
    private string variety;
    private color color;
    private int weight;
    @override
    public int compareto(apple other) {
        int result = this.variety.compareto(other.variety);
        if (result != 0) {
            return result;
        }
        if (result == 0) {
            result = this.color.compareto(other.color);
        }
        if (result != 0) {
            return result;
        }
        if (result == 0) {
            result = integer.compare(this.weight, other.weight);
        }
        return result;
    }
}
例6


在例6中,我们比较了客户指定的苹果的第一特性,它们的品种。如果compareto()调用的结果为非零,那么我们返回值。否则,我们调用另一个compareto()直到得到一个非零值,或者直到已经比较完这三个特征。尽管此代码可以工作,但它不是最有效或干净的永利汇的解决方案。在例3中,我们重构我们的代码,使其更简单。
@override
public int compareto(apple other) {
     int result = this.variety.compareto(other.variety);
     if (result == 0) {
          result = this.color.compareto(other.color);
     }
     if (result == 0) {
          result = integer.compare(this.weight, other.weight);
     }
     return result;
}
例7


正如你所看到的,这大大减少了代码,并且每一次比较只要一行代码。如果一个compareto()调用的结果是零,那么我们就转移到下一个相同if语句的比较中。顺便说一句,这是成为clean coder的一个很好的例子。通常情况下,你不需要立即写出干净的代码;你可以从一个粗略的想法开始,使其可以工作,然后不断改进,直到你尽可能得让它干净就可以了。


comparable,hashcode以及equals

你可能会注意到compareto()看起来有点像hashcode()和equals()方法。但是,它们有一个重要的区别。对于hashcode()和equals()方法,比较个体属性的顺序不影响返回的值,但是,在compareto()中,通过你比较对象的顺序来定义对象的顺序。


在结论中我只想强调comparable接口是多么的重要。它既用于java.util.arrays,也用于java.util.collections实用程序类,来排序元素和搜索排序集合中的元素。使用treeset和tree map,就更简单了——想要它们会自动排序必须实现comparable接口的元素。