浅谈Comparable与Comparator的区别

本文详细介绍了Java中Comparable与Comparator两种排序接口的区别与应用场景,并通过示例代码展示了如何使用这两种接口进行自定义排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近一直在复习Java的集合部分的东西,老师讲了很多,很受启发,在这里就简单的说说自己对于Comparable与Comparator的理解。

首先先来看看他们的使用:

先来看看Comparator的使用

将字符串数组按照字典顺序表排序:

public class StringSort {
 public static void main(String[] args) {
  String demos[]={"hello","chenhj","test","中国"};
  Arrays.sort(demos, new StringComparator());//在这里调用这个方法正是为了将制定的数组,按照一个自定义的排序器进行排
  for(String str:demos){
   System.out.println(str);
  }
 }
}

接下来就是排序器的自定义

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class StringComparator implements Comparator<String>{
 @Override
 public int compare(String o1, String o2) {
  // TODO Auto-generated method stub
  return o1.compareTo(o2);//重新定义比较的方法
 } 
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

再来看看Comparable的使用

将利用TreeMap将其中的数据按照某种规则进行排序:

 

Code类:

public class Code implements Comparable<Code>{
 private Integer id;
 public Code(Integer id) {
  this.id=id;
 }
 @Override
 public boolean equals(Object obj) {
  if(obj==null){
   return false;
  }
  if(obj instanceof Code){
   Code c=(Code)obj;
   if(c.id==this.id){
    return true;
   }
  }
  return false;
 }
 @Override
 public int hashCode() {
  
  return id;
 }
 @Override
 public String toString() {
  return "Code [id=" + id + "]";
 }

//重写其中的方法
 @Override
 public int compareTo(Code o) {
  if(this.id>o.id){
   return -1;
  }else if(this.id==o.id){
   return 0;
  }else if(this.id<o.id){
   return 1;
  }
  return 0;
 }
}

 

Person类:

public class Person {
 private Code id;//身份
 private String name;
 
 public Person(String name,Code id) {
  this.name=name;
  this.id=id;
 }
 
 @Override
 public boolean equals(Object obj) {
  if(obj==null){
   return false;
  }
  if(obj instanceof Person){
   Person p=(Person)obj;
   if(p.id==this.id){
    return true;
   }
  }
  return false;
 }
 @Override
 public String toString() {
  return "Person [id=" + id + ", name=" + name + "]";
 }

 public Code getId() {
  return id;
 }
 
}

 

测试类:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

public class MapDemo {
 public static void main(String[] args) {
  TreeMap<Code, Person> map = new TreeMap<Code, Person>();// 里面的泛型约束都是引用数据类型

  Person p1 = new Person("x", new Code(11));
  Person p2 = new Person("xz", new Code(12));
  Person p3 = new Person("xx", new Code(13));
  Person p4 = new Person("xy", new Code(14));
  Person p5 = new Person("xxy", new Code(11));

  map.put(p1.getId(), p1);
  map.put(p2.getId(), p2);
  map.put(p3.getId(), p3);
  map.put(p4.getId(), p4);
  map.put(p5.getId(), p5);

  Set<Entry<Code, Person>> entrys = map.entrySet();// 返回映射项的set视图
  Iterator<Entry<Code, Person>> its = entrys.iterator();
  while (its.hasNext()) {
   Entry<Code, Person> entry = its.next();
   System.out.println(entry.getKey() + "->" + entry.getValue());
  }
 }
}

 

看完两个不同的接口之后,我们从运行结果可以看出,一个是将字符串数组进行了排序,而另一个则是根据Code的id字段的值进行了排序。那么同样都是排序,他们之间,到底有什么区别呢?

总结一下就是:

Comparable是一个对象本身就已经支持自比较所需要实现的接口(如String Integer自己就可以完成比较大小操作)

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

 

 

TreeSet是一个有序的集合,它根据元素的自然排序进行排序。如果在创建TreeSet时没有指定Comparator,那么将使用元素的自然排序。元素的自然排序是通过实现Comparable接口来定义的。 如果元素没有实现Comparable接口,则在创建TreeSet时必须提供Comparator来定义排序顺序。Comparator可以在创建TreeSet时通过构造函数参数传递。 TreeSet使用红黑树来实现排序。红黑树是一种自平衡二叉搜索树,它保证了插入,删除,查找操作的时间复杂度为O(log n)。在红黑树中,每个节点都有一个颜色属性,它可以是红色或黑色。红黑树满足以下规则: 1. 每个节点都是红色或黑色。 2. 根节点是黑色。 3. 每个叶子节点(NIL节点,空节点)是黑色的。 4. 如果一个节点是红色的,则它的两个子节点都是黑色的。 5. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。 通过这些规则,红黑树可以保证在插入,删除,查找操作时,树的高度不会超过log2(n),因此它的时间复杂度为O(log n)。 当我们向TreeSet中添加元素时,它会按照元素的自然排序或者通过Comparator定义的排序规则,找到合适的位置插入新元素。在插入完成后,TreeSet会自动进行平衡操作,以保持红黑树的平衡性。当我们从TreeSet中删除元素时,它也会自动进行平衡操作。 总结起来,TreeSet的排序原理是通过红黑树实现的,它使用元素的自然排序或者通过Comparator定义的排序规则进行排序。在插入删除元素时,TreeSet会自动进行平衡操作,以保持红黑树的平衡性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值