Item 12 考虑实现Comparable接口

1.Comparable接口,用来做什么。

2.判定类实现的Comparable接口是否正确的方法。

3.不要扩展一个已经实现了Comparable接口的类来增加用于比较的值组件。

1.Comparable接口,用来做什么?

---Comparable接口-----
public interface Comparable<T> {

  int compareTo(T t);

}
---Comparable接口-----

Comparable接口用来做什么?实现了Comparable接口的类,具备什么功能?

“This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class‘s natural ordering, and the class‘s compareTo method is referred to as its natural comparison method.

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.

实现了Comparable接口的类,它的实例就具备了排序功能。然后,把实现了Comparable接口的类的实例,添加到List或者array集合中,调用Collections.sort或者Arrays.sort就可以得到一个排好序的集合。

一个类实现Comparable接口时,要遵守如下约定:

1.将当前对象与指定对象进行比较。当该对象小于、等于、或大于指定对象的时候,分别返回一个负整数、零或者正整数。如果由于指定对象的类型而无法与该对象进行比较,则抛出ClassCastException异常。

------这是在实现时,首要考虑的约定。按照该约定来实现Comparable接口。

例子:

选定要比较的是类中的哪个属性,下面比较的是Sal属性。

public class Employee implements Comparable<Employee> {

  private int EmpID ;
  private String Ename;
  private double Sal ;
  private static int i;

  public Employee() {
    EmpID = i++;
    Ename = "dont know";
    Sal = 0.0;
  }

  public Employee(String ename, double sal) {
    EmpID = i++;
    Ename = ename;
    Sal = sal;
  }

  public String toString() {
    return "EmpID " + EmpID + "\n" + "Ename " + Ename + "\n" + "Sal " + Sal ;
  }

  public int compareTo(Employee arg0) {
    // TODO Auto-generated method stub
    if (Sal < arg0. Sal)
      return -1;
    else if (Sal == arg0.Sal)
      return 0;
    else
      return 1;

  }
}

然后就可以使用该类了,结合List<T>,Array集合实现对集合中的元素进行排序,如下:

public class ComparableDemo {

  public static void main(String[] args) {

    List<Employee> ts1 = new ArrayList<Employee>();
    ts1.add(new Employee( "Tom", 40000.00));
    ts1.add(new Employee( "Harry", 20000.00));
    ts1.add(new Employee( "Maggie", 50000.00));
    ts1.add(new Employee( "Chris", 70000.00));
    Collections.sort(ts1);
    Iterator<Employee> itr = ts1.iterator();

    System.out.println( "------List--------");
    while (itr.hasNext()) {
      Object element = itr.next();
      System. out.println(element + "\n" );

    }

    System.out.println( "-----Array--------");
    Employee[] oneArray =
        { new Employee("Peter" , 30000.00), new Employee( "Harry", 20000.00),
            new Employee("Maggie" , 50000.00)};
    Arrays.sort(oneArray);
    for (Employee one : oneArray) {
      System. out.println(one + "\n" );
    }

  }
}

输出结果:是一个升序排序,从小到大。

------List--------

EmpID 1

Ename Harry

Sal 20000.0

EmpID 0

Ename Tom

Sal 40000.0

EmpID 2

Ename Maggie

Sal 50000.0

EmpID 3

Ename Chris

Sal 70000.0

-----Array--------

EmpID 5

Ename Harry

Sal 20000.0

EmpID 4

Ename Peter

Sal 30000.0

EmpID 6

Ename Maggie

Sal 50000.0

2.判定类实现的Comparable接口是否正确的方法

 

根据《effective Java>,在判定类实现的Comparable接口实现是否正确时,使用下列通用约定来判定:

1)实现者必须确保所有的x和y都满足sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。(这也暗示着,当且仅当y.compareTo(x)抛出异常时,x.compareTo(y)才必须抛出异常。

使用上述的例子,可以这样写个单元测试:

  Employee one = new Employee( "Tom", 40000.00);
    Employee two = new Employee("Chris", 70000.00);
    if (one.compareTo( two) == -two .compareTo(one)) {
      System. out.println("satisfy rule one." );
    }

2)实现者还必须确保这个关系时可传递的:(x.compareTo(y) > 0 && y.compareTo(z)>0),暗示着x.compareTo(z) > 0。---传递性。

使用上述的例子,可以这样写个单元测试:

  Employee x = new Employee( "Tom", 40000.00);
    Employee y = new Employee( "ChrisY", 30000.00);
    Employee z = new Employee( "Chris", 20000.00);
    if (x.compareTo(y) > 0 && y.compareTo(z) > 0 && x.compareTo(z) > 0) {

      System. out.println("satisfy rule No.two" );

    }

3)实现者必须确保x.compareTo(y) == 0暗示着所有的z都满足sgn(x.compareTo(z)) == sgn(y.compareTo(z))。

使用上述的例子,可以这样写个单元测试:

    Employee x = new Employee( "Tom", 40000.00);
    Employee y = new Employee( "ChrisY", 40000.00);
    Employee z = new Employee( "Chris", 20000.00);
    if (x.compareTo(y) == 0) {
      if (x.compareTo(z) == y.compareTo(z)) {
        System. out.println("satisfy rule No.threee" );
      }
    }

总的来说,这三条通用约定,是用来指导你编写单元测试的。如果,你实现的Compareable接口违反了这三条约定,那么,将不能完好的与List,Array等集合协作。

3.不要扩展一个已经实现了Comparable接口的类来增加用于比较的值组件

如果你想为一个实现了Comparable接口的类增加值组件,请不要扩展这个类;而是要编写一个不相关的类,其中包含第一个类的一个实例。然后提供一个“视图(view)"方法返回这个实例。这样既可以让你自由地在第二个类上实现compareTo方法,同时也允许它的客户端在必要的时候,把第二个类的实例视同第一个类的实例。

例子:假设,在比较职员的时候,还考虑到这个职员当前的级别。当两个职员的级别相等时,才比较他们的销售额;否则,则比较职员的级别,职员级别高的,排在后面,按照升序排列。

public class NewEmployee implements Comparable<NewEmployee> {

  public static final int Low = 10;
  public static final int Middle = 20;
  public static final int High = 30;

  private int EmpID ;
  private String Ename;
  private double Sal ;
  private static int i;

  private Grade oneGrade;

  public NewEmployee() {
    EmpID = i++;
    Ename = "dont know";
    Sal = 0.0;

    oneGrade = new Grade( Low );
  }

  public NewEmployee(String ename, double sal, Grade grade) {
    EmpID = i++;
    Ename = ename;
    Sal = sal;
    oneGrade = grade;
  }

  public String toString() {
    return "EmpID " + EmpID + "\n" + "Ename " + Ename + "\n" + "Sal " + Sal + "\n" + "Grade "
        + getGradeName( oneGrade.getGrade());
  }

  private String getGradeName( int grade) {
    switch (grade) {
      case Low :
        return "Low" ;
      case Middle :
        return "Middle" ;
      case High :
        return "High" ;

      default:
        return "Null" ;

    }
  }

  public int compareTo(NewEmployee arg0) {
    // TODO Auto-generated method stub

    if ( oneGrade.compareTo(arg0. oneGrade) == 0) {
      if ( Sal < arg0. Sal) {
        return -1;
      } else if (Sal == arg0. Sal) {
        return 0;
      } else {
        return 1;
      }

    } else {
      return oneGrade.compareTo(arg0. oneGrade);
    }

  }

}

--------
public class NewComparableDemo {

  public static void main(String[] args) {

    List<NewEmployee> ts1 = new ArrayList<NewEmployee>();
    ts1.add( new NewEmployee( "Tom" , 40000.00, new Grade(NewEmployee. Middle)));
    ts1.add( new NewEmployee( "Harry" , 20000.00, new Grade(NewEmployee. Low)));
    ts1.add( new NewEmployee( "Maggie" , 50000.00, new Grade(NewEmployee. High)));
    ts1.add( new NewEmployee( "Chris" , 70000.00, new Grade(NewEmployee. Low)));
    Collections. sort(ts1);
    Iterator<NewEmployee> itr = ts1.iterator();

    while (itr.hasNext()) {
      Object element = itr.next();
      System. out .println(element + "\n" );

    }

    NewEmployee x = new NewEmployee( "Tom" , 40000.00, new Grade(NewEmployee.Middle ));
    NewEmployee y = new NewEmployee( "Harry" , 20000.00, new Grade(NewEmployee.Low ));
    if (x.compareTo(y) == -y.compareTo(x)) {
      System. out .println("satisfy rule No.one" );
    }

    NewEmployee x1 = new NewEmployee( "Tom" , 40000.00, new Grade(NewEmployee.Middle ));
    NewEmployee y1 = new NewEmployee( "Harry1" , 70000.00, new Grade(NewEmployee.Low ));
    NewEmployee z1 = new NewEmployee( "Harry2" , 30000.00, new Grade(NewEmployee.Low ));
    if (x1.compareTo(y1) > 0 && y1.compareTo(z1) > 0 && x1.compareTo(z1) > 0) {
      System. out .println("satisfy rule No.two" );
    }

    NewEmployee x2 = new NewEmployee( "Tom2" , 70000.00, new Grade(NewEmployee.Middle ));
    NewEmployee y2 = new NewEmployee( "Harry2" , 70000.00, new Grade(NewEmployee.Middle ));
    NewEmployee z2 = new NewEmployee( "Harry2" , 30000.00, new Grade(NewEmployee.Low ));
    if (x2.compareTo(y2) == 0) {
      if (x2.compareTo(z2) == y2.compareTo(z2)) {
        System. out .println("satisfy rule No.three" );
      }
    }

  }
}

 

输出结果:

EmpID 1

Ename Harry

Sal 20000.0

Grade Low

EmpID 3

Ename Chris

Sal 70000.0

Grade Low

EmpID 0

Ename Tom

Sal 40000.0

Grade Middle

EmpID 2

Ename Maggie

Sal 50000.0

Grade High

satisfy rule No.one

satisfy rule No.two

satisfy rule No.three

时间: 2024-10-09 15:54:28

Item 12 考虑实现Comparable接口的相关文章

Effective Item - 谨慎实现Comparable接口

类实现了Comparable接口就表明类的实例本身具有内在的排序关系(natural ordering). 因此,该类可以与很多泛型算法和集合实现进行协作. 而我们之需要实现Comparable接口唯一的方法——compareTo. 以下是相关规则: sgn(x.compareTo(y)) = -sgn(y.compareTo(x)) (x.compareTo(y)>0 && y.compareTo(z)>0) 则 x.compareTo(z)>0 x.compareTo

Java6.0中Comparable接口与Comparator接口详解

Java6.0中Comparable接口与Comparator接口详解 说到现在,读者应该对Comparable接口有了大概的了解,但是为什么又要有一个Comparator接口呢?难道Java的开发者都吃饱撑着没事做吗? 再谈Comparator接口之前,大家应该先了解一个叫“策略模式”的东东.一下是百度百科对策略模式的描写: 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化.(原文:The Strategy Pattern

Comparable接口与Comparator接口的比较————Comparable接口详解

Comparable接口位于:java.lang包中. Comparable接口: 1. 实现了这个接口的类,会被强制进行自然排序. 问题又来了:那什么是自然排序呢? 自然排序:就是字典序排序,不分大小写.例如:a.A都排在b.B之前. 做个简单的测试吧: 现在有个需求,需要让你把用户进行自然排序.So,亲爱的小伙伴们,这应该 怎么做呢? 思路:创建一个用户类(User),且此类实现了Comparable接口,然后进行测试. 记住了呦: Collections.sort();可以对列表进行排序.

Comparable接口的实现和使用

1.什么是Comparable接口 此接口强行对实现它的每个类的对象进行整体排序.此排序被称为该类的自然排序 ,类的 compareTo 方法被称为它的自然比较方法 .实现此接口的对象列表(和数组)可以通过 Collections.sort (和 Arrays.sort )进行自动排序.实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器. 强烈推荐(虽然不是必需的)使自然排序与 equals 一致.所谓与equals一致是指对于类 C 的每一个 e1 和 e2 来说,当且

Java之Comparable接口和Comparator接口

Comparable & Comparator 都是用来实现集合中元素的比较.排序的: Comparable 是在集合内部定义的方法实现的排序: Comparator 是在集合外部实现的排序: 所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法. Comparator位于包java.util下,而Comparable位于包java.lang下 Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 Strin

Map容器——TreeMap及常用API,Comparator和Comparable接口

TreeMap及常用API ①   TreeMap类通过使用红黑树实现Map接口; ②   TreeMap提供按排序顺序存储键/值对的有效手段,同时允许快速检索; ③   不像散列(HashMap),树映射保证它的元素按关键字升序排序; ④   TreeMap构造方法: a)   TreeMap() b)   TreeMap(Comparator comp) c)   TreeMap(Map m) d)   TreeMap(SortedMap sm) ⑤   TreeMap实现SortedMap

comparable接口 和 comparator接口的特点与区别

1. Comparator 和 Comparable 相同的地方 他们都是java的一个接口, 并且是用来对自定义的class比较大小的. 什么是自定义class: 如 public class Person{ String name; int age }. 当我们有这么一个personList,里面包含了person1, person2, persion3....., 我们用Collections.sort( personList), 是得不到预期的结果的. 这时肯定有人要问, 那为什么可以排

Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器内的元素的遍历 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个I

Java中Comparator接口和Comparable接口的使用

一般情况下在实现对对象元素的数组或集合进行排序的时候会用到Comparator和Comparable接口,通过在元素所在的类中实现这两个接口中的一个,然后对数组或集合调用Arrays.sort或者Collentions.sort方法即可实现对数组或集合的排序.就sort方法里面的参数来说,实现了不同的接口则传递的参数也不尽相同.对于实现了Comparator接口的类来说,sort方法需要接受的参数不仅包括数组或集合,还要包括实现了该接口的类对象:而对实现了Comparable接口的类来说,参数不