• 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 + "
    " + "Ename " + Ename + "
    " + "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 + "
    " );
    
        }
    
        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 + "
    " );
        }
    
      }
    }
    
    输出结果:是一个升序排序,从小到大。
    ------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 + "
    " + "Ename " + Ename + "
    " + "Sal " + Sal + "
    " + "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 + "
    " );
    
        }
    
        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
  • 相关阅读:
    visual studio web开发调试禁用firefox缓存
    JSON C# Class Generator 由json字符串生成C#实体类的工具
    利用HttpHandler和Jquery进行数据库增改删查操作
    机器学习算法相关的开源架构介绍
    jquery validation plugin 中取消对指定按钮的有效性验证!
    Win7下附加sql2005数据库失败 错误代码5120的解决方法
    短地址服务goo.gl, bit.ly,x.co之间性能比较
    win7+iis7.5+asp.net下 CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 解决方案
    如何解决 The name ControlID does not exist in the current context 错误!
    mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource 错误的解决办法
  • 原文地址:https://www.cnblogs.com/ttylinux/p/4375789.html
Copyright © 2020-2023  润新知