当前位置: 首页 > 编程笔记 >

java 中Comparable与Comparator详解与比较

凌志学
2023-03-14
本文向大家介绍java 中Comparable与Comparator详解与比较,包括了java 中Comparable与Comparator详解与比较的使用技巧和注意事项,需要的朋友参考一下

java 中Comparable与Comparator详解

今天查看TreeMap的源码,发现其键必须是实现Comparable或者Comparator的接口时产生了一些兴趣,比如在TreeMap中的put方法分别对Comparable和Comparator接口分别进行处理。那么疑问就来了,Comparable和Comparator接口的区别是什么,Java中为什么会存在两个类似的接口?

  Comparable和Comparator接口都是用来比较大小的,首先来看一下Comparable的定义:

 package java.lang;
import java.util.*;
public interface Comparable<T> {
  public int compareTo(T o);
}

  Comparator的定义如下:

package java.util;
public interface Comparator<T> {
  int compare(T o1, T o2);
  boolean equals(Object obj);
}

  Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现(这句话没看懂?没关系,接下来看个例子就明白了)。若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。此外,实现 Comparable 接口的类的对象 可以用作 “有序映射 ( 如 TreeMap)” 中的键或 “有序集合 (TreeSet)” 中的元素,而不需要指定比较器。

  举例(类Person1实现了Comparable接口)

package collections;

public class Person1 implements Comparable<Person1>
{
  private int age;
  private String name;

  public Person1(String name, int age)
  {
    this.name = name;
    this.age = age;
  }
  @Override
  public int compareTo(Person1 o)
  {
    return this.age-o.age;
  }
  @Override 
  public String toString()
  {
    return name+":"+age;
  }
}

  可以看到Person1实现了Comparable接口中的compareTo方法。实现Comparable接口必须修改自身的类,即在自身类中实现接口中相应的方法。

  测试代码:

 Person1 person1 = new Person1("zzh",18);
    Person1 person2 = new Person1("jj",17);
    Person1 person3 = new Person1("qq",19);

    List<Person1> list = new ArrayList<>();
    list.add(person1);
    list.add(person2);
    list.add(person3);

    System.out.println(list);
    Collections.sort(list);
    System.out.println(list);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

  如果我们的这个类无法修改,譬如String,我们又要对其进行排序,当然String中已经实现了Comparable接口,如果单纯的用String举例就不太形象。对类自身无法修改这就用到了Comparator这个接口(策略模式)。

public final class Person2
{
  private int age;
  private String name;

  public Person2(String name, int age)
  {
    this.name = name;
    this.age = age;
  }

  @Override 
  public String toString()
  {
    return name+":"+age;
  }

  //getter and setter方法省略....
}

  如类Person2,这个类已经固定,无法进行对其类自身的修改,也修饰词final了,你也别想继承再implements Comparable,那么此时怎么办呢?在类的外部使用Comparator的接口。如下测试代码:

 Person2 p1 = new Person2("zzh",18);
    Person2 p2 = new Person2("jj",17);
    Person2 p3 = new Person2("qq",19);
    List<Person2> list2 = new ArrayList<Person2>();
    list2.add(p1);
    list2.add(p2);
    list2.add(p3);
    System.out.println(list2);
    Collections.sort(list2,new Comparator<Person2>(){

      @Override
      public int compare(Person2 o1, Person2 o2)
      {
        if(o1 == null || o2 == null)
          return 0;
        return o1.getAge()-o2.getAge();
      }

    });
    System.out.println(list2);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19] 

  这里(public static <T> void sort(List<T> list, Comparator<? super T> c) )采用了内部类的实现方式,实现compare方法,对类Person2的list进行排序。

  再譬如博主遇到的真实案例中,需要对String进行排序,且不区分大小写,我们知道String中的排序是字典排序,譬如:A a D排序之后为A D a,这样显然不对,那么该怎么办呢?同上(下面代码中的list是一个String的List集合):

 Collections.sort(list, new Comparator<String>()
    {
      @Override
      public int compare(String o1, String o2)
      {
        if(o1 == null || o2 == null)
          return 0;
        return o1.toUpperCase().compareTo(o2.toUpperCase());
      }
    });

  这样就可以实现不区分大小进行排序String的集合了,是不是很方便~

  细心的同学可能会有疑问,明明在Comparator接口中定义了两个方法,为什么继承的时候只实现了一个方法,难道要颠覆我对Java接口常识的理解了嚒?

  实际上,我们知道当一个类没有显式继承父类的时候,会有一个默认的父类,即java.lang.Object,在Object类中有一个方法即为equals方法,所以这里并不强制要求实现Comparator接口的类要实现equals方法,直接调用父类的即可,虽然你显式的实现了equals()方法 will be a better choice~

  在《Effective Java》一书中,作者Joshua Bloch推荐大家在编写自定义类的时候尽可能的考虑实现一下Comparable接口,一旦实现了Comparable接口,它就可以跟许多泛型算法以及依赖于改接口的集合实现进行协作。你付出很小的努力就可以获得非常强大的功能

  事实上,Java平台类库中的所有值类都实现了Comparable接口。如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者按年代顺序,那你就应该坚决考虑实现这个接口。

  compareTo方法不但允许进行简单的等同性进行比较,而且语序执行顺序比较,除此之外,它与Object的equals方法具有相似的特征,它还是一个泛型。类实现了Comparable接口,就表明它的实例具有内在的排序关系,为实现Comparable接口的对象数组进行排序就这么简单: Arrays.sort(a);

  对存储在集合中的Comparable对象进行搜索、计算极限值以及自动维护也同样简单。列如,下面的程序依赖于String实现了Comparable接口,它去掉了命令行参数列表中的重复参数,并按字母顺序打印出来:

public class WordList{
  public static void main(String args[]){
    Set<String> s = new TreeSet<String>();
    Collections.addAll(s,args);
    System.out.println(s);
  }
}

  Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。

  前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。

  我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

 类似资料:
  • 本文向大家介绍Java Comparable 和 Comparator 的详解及区别,包括了Java Comparable 和 Comparator 的详解及区别的使用技巧和注意事项,需要的朋友参考一下 Java Comparable 和 Comparator 的详解及区别 Java 中为我们提供了两种比较机制:Comparable 和 Comparator,他们之间有什么区别呢?今天来了解一下。

  • 本文向大家介绍浅析Java中comparator接口与Comparable接口的区别,包括了浅析Java中comparator接口与Comparable接口的区别的使用技巧和注意事项,需要的朋友参考一下 Comparable 简介 Comparable 是排序接口。 若一个类实现了Comparable接口,就意味着“该类支持排序”。  即然实现Comparable接口的类支持排序,假设现在存在“实

  • 问题内容: 我写了一些简单的代码,如下所示。此类运行良好,没有任何错误。 如代码注释所示,该方法应传递type参数。 但是实现接口- 不是 。 这怎么工作?该方法说它需要一个参数,但是可以与参数一起使用。 我知道我误解了一些东西,但是现在我知道了。有人可以解释一下吗? 问题答案: 上面的代码片段在逻辑上等效于以下内容: 从逻辑上讲,这也等效于以下内容: 是一个功能接口,可以用作lambda或方法引

  • 本文向大家介绍对比Java中的Comparable排序接口和Comparator比较器接口,包括了对比Java中的Comparable排序接口和Comparator比较器接口的使用技巧和注意事项,需要的朋友参考一下 Comparable Comparable 是排序接口。 若一个类实现了Comparable接口,就意味着“该类支持排序”。 即然实现Comparable接口的类支持排序,假设现在存在

  • 问题内容: 我头疼,调试困难。我正在尝试比较两个通用值,以便可以根据值将它们插入到数组中进行排序。这是我第一次使用Comparable和Comparator界面,因此围绕这些问题的任何其他建议都是不错的选择。 这是我的班级设置方式: put()方法: 这些是我要实现的compareTo()和compare方法。 我遇到的第一个问题是compareTo()方法中的问题,它以“ this”为中心。该错

  • 本文向大家介绍Java中Comparable和Comparator之间的区别,包括了Java中Comparable和Comparator之间的区别的使用技巧和注意事项,需要的朋友参考一下 比较器和比较器都是可用于对集合元素进行排序的接口。比较器接口属于java.util包,而可比较的接口属于java.lang包。比较器接口使用提供给它的两个对象进行排序收集,而可比较接口比较“this”是指提供给它

  • 本文向大家介绍Java Comparator比较器实例解析,包括了Java Comparator比较器实例解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java Comparator比较器实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 说几点需要注意的,提醒自己即可: 以下是单独定义一个比较器的类,实现了Comparat

  • 本文向大家介绍java中ArrayList与LinkedList对比详情,包括了java中ArrayList与LinkedList对比详情的使用技巧和注意事项,需要的朋友参考一下  ArrayList,LinkedList都是Collection接口的通用实现方式,两者采用了不用的存储策略,用来适应不同场合的需要。 实现方式   ArrayList的内部采用集合的方式存储数据 唯一需要注意的是对于