为什么使用嵌套类来实现Comparator?

时间:2013-07-09 03:00:35

标签: java comparator comparable

通过String的docjar,我碰巧看到了以下代码:

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();

private static class CaseInsensitiveComparator
                       implements Comparator<String>, java.io.Serializable {
    // use serialVersionUID from JDK 1.2.2 for interoperability
    private static final long serialVersionUID = 8575799808933029326L;

    public int compare(String s1, String s2) {
        // ...
    }
}

我的问题是,为什么我们不能像Comparator一样实现Comparable,并使用私有方法而不是嵌套类?

另外,在旁注中,Comparator为什么compareTo的{​​{1}}的单个参数与Comparable的参数类似?

6 个答案:

答案 0 :(得分:6)

因为String 不是 a Comparator。当然,它们确实是Comparable,但它们本身并不是“比较函数” 1 :让String实现Comparator毫无意义。

另一方面,CaseInsensitiveComparator 特定的比较函数,仅与字符串有关。因此,它被声明为static嵌套类。


1 请参阅Comparator

答案 1 :(得分:1)

您只能实现一个相同类型的接口。 String已经实现了可比较的词典比较:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{

但它需要更多compareTo方法(例如:执行不区分大小写的比较)。下面会给你编译错误:

public final class String
    implements java.io.Serializable, Comparable<String>, Comparable<String>, CharSequence
{

因此,这可能是它增加比较器的一个原因。

比较器的概念是一个在两个项目之间提供比较服务的对象,而不是一个与另一个项目相当的合同(类似的界面)

在String上实现Comparator会编译,但这将是语义错误

public final class String
    implements java.io.Serializable, Comparable<String>, Comparator<String>, CharSequence
{

答案 2 :(得分:1)

  

我的问题是为什么我们不能只实现比较器,就像可比较而使用私有函数而不是内部类?

嗯(几乎)Comparator接口的重点是接口的实现是与被比较对象的类的单独类。

从理论上讲,你可以做你想要的,但最终的结果是反直觉的

public class MyKey implements Comparator<MyKey> {
    private String field;

    public boolean compare(MyKey m1, MyKey m2) {
        // We must ignore this.field!  We are comparing m1 and m2 ...
        return m1.field.compareTo(m2.field);
    }
}

MyKey[] keys = ...
Arrays.sort(keys, new MyKey());  // Note we have to pass an instance
                                 // to provide the Comparator.

除了有点违反直觉之外,你的想法在某种意义上是有限的,即MyKey只能“通过这种方式”提供一个比较器。

坦率地说,如果你打算这样做,更有意义MyKey实现Comparable<MyKey>


假设他们按照您提议的方式实施了String。然后这......

   String[] strings = new String[]{"a", "c", "B"};
   Arrays.sort(strings);

...表示区分大小写,但是......

   String[] strings = new String[]{"a", "c", "B"};
   Arrays.sort(strings, "weasel");

...意味着不区分大小写。那个真的会让你觉得好吗? <强>真的吗

答案 3 :(得分:0)

将此作为一个类而不是一个函数允许我们将不同的比较策略多态地应用于集合(或可能正在执行比较的其他类)。这样,使用比较器的方法不需要知道它是区分大小写的比较器还是不区分大小写的比较器或其他东西;它只是执行比较。但是,如果这是一个函数,那么这种多态性将不适用。执行比较的方法要么必须使用“比较”方法,要么必须知道正在执行何种比较,以便选择正确的方法。

有两个参数而不是将第一个参数绑定到一个特定的String允许我们在任意数量的字符串上使用相同的比较器。否则,在处理大型集合时,我们必须跟踪许多比较器。它还允许在左侧或右侧(或两者)使用该比较器的子类;只有一个参数就没有那种灵活性。

答案 4 :(得分:0)

主要原因是公开Comparator对象,例如TreeMap,其中String可用作键,或其他对象,其中排序或不同类型的相等是有用。它不能是static方法,因为Comparator接口不能指定static方法,Comparator必须是实现要使用的接口的对象在像TreeMap这样的课程中。我们需要一个不区分大小写的单独的,因为默认比较(由Comparable的方法实现)已经通过区分大小写的比较。

答案 5 :(得分:0)

  

为什么我们不能只实现比较器,就像可比较和使用一样   私有函数而不是内部类

String class实现Comparable<String>接口,用于按字典顺序比较两个字符串,这是比较两个字符串的常用方法。

但是,有时您需要以不同的方式比较两个字符串,例如比较它们而忽略区分大小写。 Comparator接口提供了一种以不同方式比较两个对象的方法。在这种情况下,CaseInsensitiveComparator已实现以提供此功能,并在String.compareToIgnoreCase()方法中使用。