Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

Comparator位于包java.util下,而Comparable位于包 java.lang下 Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口) 自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。

而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。 可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。 用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。 比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。

小结:Comparatable接口必须由需要排序的多元素类本身来实现,且在其内部重写comparaTo()方法;Comparator接口是在需要排序的多元素类的外部(即使用外部类)来实现,且必须在该外部类中重写compara()方法。

两者的比较

    comparable接口:

  • 优点:对于单元素集合可以实现直接排序
  • 缺点:对于多元素排序,排序依据是固定不可更改的。(元素内部只能实现一次compareTo方法)
      comparator接口:

    • 元素的排序依据时刻变的,所以可以通过定义多个外部类的方式来实现不同的排序。使用时按照需求选取。
    • 创建外部类的代价太大。

实例:

1、实现Comparable接口(类内部实现比较函数)

需要比较的实体类:

 public class Student implements Comparable<Student> {

     private String name;
private int age; public Student(String name, int age){
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;
} @Override//类内部实现比较,因此在数组比较时只要传递一个对象数组
public int compareTo(Student o) {
return this.name.compareTo(o.name);
} public String toString(){
return "Student name ="+name+" age = "+age;
} }

执行排序:

 import java.util.Arrays;

 public class RunComparable {

     public static void main(String args[]){
Student stu[] = new Student[5];
stu[0] = new Student("hoojjack",20);
stu[1] = new Student("hoojj",24);
stu[2] = new Student("oojjack",19);
stu[3] = new Student("jjack",21);
stu[4] = new Student("ack",28);
for(int i=0;i<stu.length;i++)
System.out.println(stu[i].toString());
System.out.println("---------------");
Arrays.sort(stu);
for(int i=0;i<stu.length;i++)
System.out.println(stu[i].toString());
} }

结果:

 //以name排序
Student name =hoojjack age = 20
Student name =hoojj age = 24
Student name =oojjack age = 19
Student name =jjack age = 21
Student name =ack age = 28
---------------
Student name =ack age = 28
Student name =hoojj age = 24
Student name =hoojjack age = 20
Student name =jjack age = 21
Student name =oojjack age = 19

2、实现Comparator接口(需要自己单独新建一个类来写比较方法)

实体类:

 public class Student {

     private String name;
private int age; public Student(String name, int age){
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 String toString(){
return "Student name ="+name+" age = "+age;
}

单独实现的比较类需要继承Comparator类,以按年龄排序:

 import java.util.Comparator;

 public class StudentComparator implements Comparator<Student> {

     @Override
public int compare(Student o1, Student o2) {
if(o1.getAge()>o2.getAge())
return 1;
else if(o1.getAge()<o2.getAge())
return -1;
else
return 0;
} }

执行排序:

 import java.util.Arrays;

 public class RunComparable {

     public static void main(String args[]){
Student stu[] = new Student[5];
stu[0] = new Student("hoojjack",20);
stu[1] = new Student("hoojj",24);
stu[2] = new Student("oojjack",19);
stu[3] = new Student("jjack",21);
stu[4] = new Student("ack",28);
for(int i=0;i<stu.length;i++)
System.out.println(stu[i].toString());
System.out.println("---------------");
Arrays.sort(stu,new StudentComparator());//唯一区别的地方
for(int i=0;i<stu.length;i++)
System.out.println(stu[i].toString());
} }

结果:

 //按age排序
Student name =hoojjack age = 20
Student name =hoojj age = 24
Student name =oojjack age = 19
Student name =jjack age = 21
Student name =ack age = 28
---------------
Student name =oojjack age = 19
Student name =hoojjack age = 20
Student name =jjack age = 21
Student name =hoojj age = 24
Student name =ack age = 28

Java源码中的Arrays实现方法:

 //------1------
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
 //-----2-------
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) {
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}
 //------3------
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
T[] work, int workBase, int workLen) {
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
countRunAndMakeAscending函数如4、binarySort函数如5所示
 //-------4--------
private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
Comparator<? super T> c) {
assert lo < hi;
int runHi = lo + 1;
if (runHi == hi)
return 1; // Find end of run, and reverse range if descending
if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
runHi++;
reverseRange(a, lo, runHi);
} else { // Ascending
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
runHi++;
} return runHi - lo;
}
 //--------5-------
@SuppressWarnings("fallthrough")
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
T pivot = a[start]; // Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right; /*
* The invariants still hold: pivot >= all in [lo, left) and
* pivot < all in [left, start), so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
switch (n) {
case 2: a[left + 2] = a[left + 1];
case 1: a[left + 1] = a[left];
break;
default: System.arraycopy(a, left, a, left + 1, n);
}
a[left] = pivot;
}
}

Comparable 与 Comparator的区别的更多相关文章

  1. Java中Comparable和Comparator接口区别分析

    Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...

  2. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

  3. Comparable和Comparator的区别&Collections.sort的两种用法

    在Java集合的学习中,我们明白了: 看到tree,可以按顺序进行排列,就要想到两个接口.Comparable(集合中元素实现这个接口,元素自身具备可比性),Comparator(比较器,传入容器构造 ...

  4. 面试----java基础集合---------------------comparable和comparator 的区别

    comparable接口     是主要是用来自定义类存储在主要是TreeSet,TreeMap(键)集合中存储时,自定通过实现这种接口得到自然排序的功能. comparator 接口  是主要是用来 ...

  5. 浅谈Comparable与Comparator的区别

    平时进行自定义排序一直使用实现Comparable接口,一段时间后操作的时候居然发现有了个Comparator接口 上网差了些资料,总结笔记一下. 基本原理就是比较,底层是二叉树 比如是3,6,5,1 ...

  6. PAT——1055. 集体照 (比较comparable和comparator的区别)

    拍集体照时队形很重要,这里对给定的N个人K排的队形设计排队规则如下: 每排人数为N/K(向下取整),多出来的人全部站在最后一排: 后排所有人的个子都不比前排任何人矮: 每排中最高者站中间(中间位置为m ...

  7. Comparable和Comparator的区别

    Comparable Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较 ...

  8. 你能说说Java中Comparable和Comparator的区别吗

    之前面试中被问到这个问题,当时不屑(会)回答,下来特意查了查,整理如下. Java 中为我们提供了两种比较机制:Comparable 和 Comparator,二者都是用来实现对象的比较.排序. 下面 ...

  9. Comparable与Comparator的区别

    Java的Comparator和Comparable当需要排序的集合或数组不是单纯的数字型时,通常可以使用Comparator或Comparable,以简单的方式实现对象排序或自定义排序. 一.Com ...

随机推荐

  1. e668. 在一组像素中创建缓冲图像

    This example demonstrates how to convert a byte array of pixel values that are indices to a color ta ...

  2. REFLECTOR和FILEDISASSEMBLER的下载与使用

    .NET Reflector 下载地址 http://www.aisto.com/roeder/dotnet FileDisassembler 下载地址 http://www.denisbauer.c ...

  3. javascript -- 原型对象

    原型对象: 每个对象都有一个参考对象,这个参考对象称之为原型对象.原型对象有自己的属性和方法.当A是B的原型对象时,那 么B拥有A中的所有属性和方法. 原型对象的工作原理: 使用原型对象定义一个新的对 ...

  4. gen_server的模板

    -module(first_gen_server).-behaviour(gen_server).-export([init/1, handle_call/3, handle_cast/2, hand ...

  5. 【Java面试题】39 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

    1.什么是Set?(what) Set是Collection容器的一个子接口,它不允许出现重复元素,当然也只允许有一个null对象. 2.如何来区分重复与否呢?(how) “ 用 iterator() ...

  6. 最有价值的50道java面试题 适用于准入职Java程序员

    下面的内容是对网上原有的Java面试题集及答案进行了全面修订之后给出的负责任的题目和答案,原来的题目中有很多重复题目和无价值的题目,还有不少的参考答案也是错误的,修改后的Java面试题集参照了JDK最 ...

  7. 怎样用MathType输入带分数

    MathType作为一种常用的数学公式编辑器.虽然其操作已经很简单了,但是对于刚刚接触MathType的新用户来说,一些最基本的MathType输入也是有一定难度的,一些人在MathType分数的编辑 ...

  8. opencv-从图像旋转学习Mat数据訪问

    先看一个简单的样例 代码: // ConsoleApplication3_6_23.cpp : Defines the entry point for the console application. ...

  9. [笔试题]MS 2014

    http://blog.csdn.net/xiaoerlyl/article/details/12126807 别人写的答案: http://blog.csdn.net/zhou2214/articl ...

  10. org.apache.activemq.transport.InactivityIOException: Cannot send, channel has already failed

    项目是使用activeMQ 发布订阅的模式,在本地测试正常,但是 放到服务器上出现这个错误: org.apache.activemq.transport.InactivityIOException: ...