java.lang.Comparable接口详解

public interface Comparable<T>此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与 e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals 一致。注意,null 不是任何类的实例,即使 e.equals(null) 返回 false,e.compareTo(null) 也将抛出 NullPointerException。

建议(虽然不是必需的)最好使自然排序与 equals 一致。这是因为在使用自然排序与 equals 不一致的元素(或键)时,没有显式比较器的有序集合(和有序映射表)行为表现“怪异”。尤其是,这样的有序集合(或有序映射表)违背了根据 equals 方法定义的集合(或映射表)的常规协定。

例如,如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。

实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等。

从数学上讲,定义给定类 C 上自然排序的关系式 如下:

{(x, y)|x.compareTo(y) <= 0}。
整体排序的商 是:
{(x, y)|x.compareTo(y) == 0}。
它直接遵循 compareTo 的协定,商是 C 的等价关系,自然排序是 C 的整体排序。当说到类的自然排序与 equals 一致 时,是指自然排序的商是由类的 equals(Object) 方法定义的等价关系。

{(x, y)|x.equals(y)}。此接口是 Java Collections Framework 的成员。

java.lang.Comparable 接口定义的 compareTo() 方法用于提供对其实现类的对象进行整体排序所需要的比较逻辑。
实现类基于 compareTo() 方法的排序被称为自然排序。而 compareTo() 方法的排序被称为它的自然排序。具体的排序原则可由实现类根据需要而定。用户在重写 compareTo() 方法以定制比较逻辑时,需要确保其余等价性判断方法 equals() 保持一致,即 e1.equals((Object)e2) 和e1.compareTo((Object)e2)==0 具有相同的值,这样的话我们就称自然顺序就和 equals 一致。


这个接口有什么用呢?
如果一个数组中的对象实现了 Compareable 接口,则对这个数组进行排序非常简单: Arrays.sort(); 如果 List 实现了该接口的话 , 我们就可以调用Collections.sort 或者 Arrays 方法给他们排序。实际上 Java 平台库中的所有值类 (value classes) 都实现了 Compareable 接口。
Comparable 接口只有一个方法 compareTo(Object obj)
其中
this < obj 返回负
this = obj 返回 0
this > obj 返回正
即将当前这个对象与指定的对象进行顺序比较,当该对象小于、等于或大于指定对象时,分别返回一个负整数、 0 或正整数,如果无法进行比较,则抛出ClassCastException 异常。

其实,有两种方式可以进行集合排序 :
1. 集合中对象的所属类实现了 java.lang.Comparable 接口
2. 为集合指定比较器 java.lang.Comparator 的实现类


Comparator , Comparable 接口的区别是:
comparable 是通用的接口,用户可以实现它来完成自己特定的比较,而 comparator 可以看成一种算法的实现,在需要容器集合 collection 需要比较功能的时候,来指定这个比较器,这可以看出一种设计模式,将算法和数据分离,就像 C++ STL 中的函数对象一样。
前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于“静态绑定”,而后者可以“动态绑定”。
一个类实现了 Camparable 接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用 Sort 方法排序了。
而 Comparator 的作用有两个:
   1. 如果类的设计师没有考虑到 Compare 的问题而没有实现 Comparable 接口,可以通过  Comparator 来实现比较算法进行排序
2. 为了使用不同的排序标准做准备,比如:升序、降序或其他什么序.

[java]
package com.itm.test; 
 
/***********
         利用 Comparable 接口创建自己的类的排序顺序,只是实现 compareTo() 方法的问题。
         
         通常就是依赖几个数据成员的自然排序。同时类也应该覆盖 equals() 和 hashCode() 以确保两个相等的对象返回同一个哈希码。
        
        这个接口的作用:如果数组或者集合中的(类)元素实现了该接口的话 , 
        
        我们就可以调用 Collections.sort 和 Arrays.sort 排序,或应用于有序集合 TreeSet 和 TreeMap 中。
 * @author 
 *
 */ 
@SuppressWarnings("unchecked") 
public class Person implements java.lang.Comparable{ 
     
    private final int id; 
     
    private String name; 
     
    private int age; 
     
    public Person(int id,String name,int age){ 
        super(); 
        this.id = id; 
        this.name = name; 
        this.age = age; 
    } 
     
     
 
    public String getName() { 
        return name; 
    } 
 
 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
 
 
    public int getAge() { 
        return age; 
    } 
 
 
 
    public void setAge(int age) { 
        this.age = age; 
    } 
 
 
 
    public int getId() { 
        return id; 
    } 
 
    public String toString(){ 
        return "Id: " + id + "/tName: " + name + "/tAge: " + age; 
    }     
 
     
    // 实现 Comparable 接口的抽象方法,定义排序规则  
    @Override 
    public int compareTo(Object o) { 
         
        Person per = (Person)o; 
        return this.id - per.id; 
    } 
 
     

package com.itm.test;

/***********
   利用 Comparable 接口创建自己的类的排序顺序,只是实现 compareTo() 方法的问题。
  
   通常就是依赖几个数据成员的自然排序。同时类也应该覆盖 equals() 和 hashCode() 以确保两个相等的对象返回同一个哈希码。 www.2cto.com
  
  这个接口的作用:如果数组或者集合中的(类)元素实现了该接口的话 ,
  
  我们就可以调用 Collections.sort 和 Arrays.sort 排序,或应用于有序集合 TreeSet 和 TreeMap 中。
 * @author
 *
 */
@SuppressWarnings("unchecked")
public class Person implements java.lang.Comparable{
 
 private final int id;
 
 private String name;
 
 private int age;
 
 public Person(int id,String name,int age){
  super();
  this.id = id;
  this.name = name;
  this.age = age;
 }
 
 

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public int getId() {
  return id;
 }

 public String toString(){
        return "Id: " + id + "/tName: " + name + "/tAge: " + age;
 }   

 
 // 实现 Comparable 接口的抽象方法,定义排序规则
 @Override
 public int compareTo(Object o) {
  
  Person per = (Person)o;
  return this.id - per.id;
 }

 
}

[java]
package com.itm.test; 
 
import java.util.TreeSet; 
 
public class TestComparable { 
 
    /**
     * @param args
     */ 
    @SuppressWarnings("unchecked") 
    public static void main(String[] args) { 
        TreeSet tree = new TreeSet(); 
        tree.add(new Person(1,"小名",15)); 
        tree.add(new Person(4,"小刚",16)); 
        tree.add(new Person(3,"小花",17)); 
        tree.add(new Person(2,"金刚",100)); 
         
//      Iterator it = tree.iterator();  
//      while(it.hasNext()){  
//          Person employee = (Person) it.next();  
//          System.out.println(employee);  
//      }  
         
        for(Object o : tree){ 
            System.out.println(o); 
        } 
 
    } 
 

package com.itm.test;

import java.util.TreeSet;

public class TestComparable {

 /**
  * @param args
  */
 @SuppressWarnings("unchecked")
 public static void main(String[] args) {
  TreeSet tree = new TreeSet();
  tree.add(new Person(1,"小名",15));
  tree.add(new Person(4,"小刚",16));
  tree.add(new Person(3,"小花",17));
  tree.add(new Person(2,"金刚",100));
  
//  Iterator it = tree.iterator();
//  while(it.hasNext()){
//   Person employee = (Person) it.next();
//   System.out.println(employee);
//  }
  
  for(Object o : tree){
   System.out.println(o);
  }

 }

}


说到现在,读者应该对Comparable接口有了大概的了解,但是为什么又要有一个Comparator接口呢?难道Java的开发者都吃饱撑着没事做吗?

再谈Comparator接口之前,大家应该先了解一个叫“策略模式”的东东。一下是百度百科对策略模式的描写:

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)


之所以要谈到策略模式,就是因为Comparator接口其实就是一种策略模式的实践。实现Comparator接口的类必然就会实现一个compareTo(Object o1, Object o2)的方法,而这个方法就是算法中的一部分,所有使用了compareTo方法的类都不会关心compareTo是如何工作的,只关心他的返回值,这也是面向对象中著名的封装特性。

那Comparator接口应该如何使用呢?别急,首先我们要先对Person类进行一下处理,因为我们现在使用Comparator接口,所以Comparable接口就可以光荣的退休了

原文地址:https://www.cnblogs.com/appzhang/p/2690482.html