JAVA学习之Comparable与Comparator接口

 public interface Comparator<T>
此接口提供对某个collection集合对象进行强行整体排序的比较函数。可以将 Comparator 传递给 sort() 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现自定义精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的collection集合对象提供排序。
 
public interface Comparable<T>
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。这些元素组成的有序对象列表的顺序就叫做自然顺序。实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
 
public class TreeSet<E>extends AbstractSet<E>implements NavigableSet<E>, Cloneable, Serializable
Set接口中的元素是无序的(说无序是因为添加和顺序和元素取出的顺序是不一致的),但是TreeSet里面的元素是相对有序的,可以按照某种要求对集合中的元素进行排序,使用元素的自然顺序对元素进行排序要求实现Comparable接口,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。此实现为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。即对Set集合的添加,删除,检查是否包含操作都会调用自然比较或比较器的比较方法.
 
TreeSet有两种实现排序的方式:
(1). 让元素本身具有比较性,即集合中的元素每个都能和另一个元素进行比较,
       元素本身要实现Comparable接口并实现里面的compareTo方法以保证元素本身具有比较性,
  int compareTo(T o)比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。 
(2). 让容器自身具有比较性,即集合主动来对集合中的每个元素进行排序,
       当元素本身不具有比较性或者具备的比较性不是所需要的,就在TreeSet建立实例的时候,传入Comparator接口的实现子类的实例。这个Comparator子类必须实现compare方法。
  int compare(T o1,T o2)比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
 
在TreeSet集合添加元素的时候,如果要添加的元素的类型没有实现Comparable的话,而又没有在Set初始化的时候指定Comparator时,在运行的时候会出现类型转换出错"java.lang.ClassCastException"的异常,所以我们要为这个集合中元素的类型实现Comparable接口,即为这个类型添加一个自然排序方法.
 
但是有些时候我们不想在实体类中实现Comparable接口的话,或者有些实体类不方便修改的时候,再或者我们对这些类提供的自然排序方法不满意的时候,我们就可以使用Comparator接口了,然后在TreeSet初始化时选择可以提供比较器的构造函数
TreeSet(Comparator<? super E> comparator) 
构造一个新的空 TreeSet,它根据指定比较器进行排序。
这时可以定义一个实现了Comparator接口的类,或者直接使用一个匿名类来对Set集合中的元素进行排序.
 
这里我们定义一个员工类,这个员工类实现了Comparable接口,提供了自然排序方法,是按工号排序的,如果工号重复,则元素不添加,因为Set集合的元素是唯一的.
// 员工类,实现Comparable接口,如果没有实现的话,直接在Set集合中添加这个类型的元素会出现类型转换出错的异常
class Employee implements Comparable
{
    // 如果没有实现这个接口方法时,Set集合添加元素时会出错
    @Override
    public int compareTo(Object arg0)
    {
        // TODO Auto-generated method stub
        Employee e = (Employee) arg0;
        return this.number.compareTo(e.getNumber());
    }

    // 姓名
    private String name;
    // 工号
    private String number;

    public Employee(String _name, String _number)
    {
        this.name = _name;
        this.number = _number;
    }

    // 以下为对应的get.set方法
    public String getName()
    {
        return name;
    }

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

    public String getNumber()
    {
        return number;
    }

    public void setNumber(String number)
    {
        this.number = number;
    }

}


在使用自然排序的时候.
import java.util.*;

public class Test1
{
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        Set set = new TreeSet();
        set.add(new Employee("王五""03"));
        set.add(new Employee("赵六""04"));
        set.add(new Employee("张三""01"));
        set.add(new Employee("李四""02"));
        set.add(new Employee("田七""05"));
        set.add(new Employee("赵六1""04"));
        set.add(new Employee("田七1""05"));

        for (Object s : set)
        {
            Employee e = (Employee) s;
            System.out.println(e.getName() + ":" + e.getNumber());
        }
    }
}

// 

测试代码运行结果是:

 

 
添加了7个元素,工号是乱的,并且有两个工号重复,最后得出的结果是,重复工号的两个元素没有添加成功,其它元素按工号排序,
--------------------------------------------------------------------------------------------------------------------------
 
下面是使用比较器进行排序的代码
import java.util.*;
public class Test1
{
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        Set set = new TreeSet(new MyComparator());
        set.add(new Employee("王五""03"));
        set.add(new Employee("赵六""04"));
        set.add(new Employee("张三""01"));
        set.add(new Employee("李四""02"));
        set.add(new Employee("田七""05"));
        set.add(new Employee("赵六1""04"));
        set.add(new Employee("田七1""05"));
        set.add(new Employee("田七""005"));

        for (Object s : set)
        {
            Employee e = (Employee) s;
            System.out.println(e.getName() + ":" + e.getNumber());
        }
    }
}

class MyComparator implements Comparator
{

    @Override
    public int compare(Object arg0, Object arg1)
    {
        Employee e1 = (Employee) arg0;
        Employee e2 = (Employee) arg1;

        return e1.getName().compareTo(e2.getName());
    }

}

// 

结果是:

 

也可以在TreeSet初始化的时候使用匿名类进行排序.
如:

 //


import java.util.*;
public class Test1
{
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        Set set = new TreeSet(new Comparator()
        {
            public int compare(Object arg0, Object arg1)//直接在初始化方法中使用匿名类来实现比较器功能
            {
                Employee e1 = (Employee) arg0;
                Employee e2 = (Employee) arg1;
                return e1.getName().compareTo(e2.getName());
            }
        });
        set.add(new Employee("王五""03"));
        set.add(new Employee("赵六""04"));
        set.add(new Employee("张三""01"));
        set.add(new Employee("李四""02"));
        set.add(new Employee("田七""05"));
        set.add(new Employee("赵六1""04"));
        set.add(new Employee("田七1""05"));
        set.add(new Employee("田七""005"));

        for (Object s : set)
        {
            Employee e = (Employee) s;
            System.out.println(e.getName() + ":" + e.getNumber());
        }
    }
}

 JAVA中的大多数的类型都已经实现了Comparable接口,比如String和Integer,都有compareTo()方法,以上的实例代码中也是直接使用了String类的这个方法来进行比较的,

但是在一般情况下还是推荐使用Comparator接口,因为现在有很多的实例类是没有实现Comparable接口的,但是我们又想要对元素进行排序,而且写匿名类的方法也挺方便的.
原文地址:https://www.cnblogs.com/fylx/p/3985730.html