数据结构Java版对象的比较之Comparable与Comparator比较器
Posted 小熊爱吃软糖吖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构Java版对象的比较之Comparable与Comparator比较器相关的知识,希望对你有一定的参考价值。
目录
1.实现Comparable接口,重写compareTo方法
一、基本类型的比较
在Java中,基本类型的对象可以直接比较大小。基本类型byte、short、int、long、float、double、boolean、char
public class TestCompare
public static void main(String[] args)
int a = 10;
int b = 20;
System.out.println(a > b);
System.out.println(a < b);
System.out.println(a == b);
char c1 = 'A';
char c2 = 'B';
System.out.println(c1 > c2);
System.out.println(c1 < c2);
System.out.println(c1 == c2);
boolean b1 = true;
boolean b2 = false;
System.out.println(b1 == b2);
System.out.println(b1 != b2);
二、对象类型的比较
(1)对象类型比较出现的问题
class Card
public int rank; // 数值
public String suit; // 花色
public Card(int rank, String suit)
this.rank = rank;
其4this.suit = suit;
public class TestPriorityQueue
public static void main(String[] args)
Card c1 = new Card(1, "♠");
Card c2 = new Card(2, "♠");
Card c3 = c1;
//System.out.println(c1 > c2); // 编译报错
System.out.println(c1 == c2); // 编译成功 ----> 打印false,因为c1和c2指向的是不同对象
//System.out.println(c1 < c2); // 编译报错
System.out.println(c1 == c3); // 编译成功 ----> 打印true,因为c1和c3指向的是同一个对象
c1、c2和c3分别是Card类型的引用变量,上述代码在比较编译时:
c1 > c2 编译失败
c1== c2 编译成功
c1 < c2 编译失败
从编译结果可以看出,Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。
==的比较:
基本类型 比较元素内容
引用类型 比较引用变量的地址
对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法,但是该方法的比较规则是:不是比较引用变量或者引用对象的内容,而是直接比较引用变量的地址,但有些情况下该种比较就不符合题意。就需要重写equals方法。
// Object中equal的实现,可以看到:直接比较的是两个引用变量的地址
public boolean equals(Object obj)
return (this == obj);
(2)重写基类equals方法
instanceof小贴士:
instanceof是Java的一个二元操作符(运算符),和==,>,<是同一类东西。由于它是由字母组成的,所以也是Java的保留关键字。它的作用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据。可以用来判断继承中的子类的实例是否为父类的实现。相当于c#中的is操作符。java中的instanceof是通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。
public class Card
public int rank; // 数值
public String suit; // 花色
public Card(int rank, String suit)
this.rank = rank;
this.suit = suit;
@Override
public boolean equals(Object o)
//自己和自己比较
if(this==o)
return true;
//o对象为null或者o不属于Card子类
if(o==null||!(o instanceof Card))
return false;
Card c= (Card) o;
return rank==c.rank&&suit.equals(c.suit);
重写equals的步骤:
1. 如果指向同一个对象,返回 true
2. 如果传入的为 null,返回 false
3. 如果传入的对象类型不是 Card,返回 false
4. 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌
5. 注意下调用其他引用类型的比较也需要 equals,例如这里的 suit 的比较。
重写基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。
(3)基于Comparable接口的比较
1.实现Comparable接口,重写compareTo方法
Comparable是JDK提供的泛型的比较接口类,源码实现具体如下:
Compareble是java.lang中的接口类,可以直接使用
public interface Comparable<E>
int compareTo(E o);
具体用法:通过comparaTo方法的返回值来判断
comparaTo方法的返回值:
< 0: 表示 this 指向的对象小于 o 指向的对象
== 0: 表示 this 指向的对象等于 o 指向的对象
> 0: 表示 this 指向的对象大于 o 指向的对象
public class Card implements Comparable<Card>
public int rank; // 数值
public String suit; // 花色
public Card(int rank, String suit)
this.rank = rank;
this.suit = suit;
// 根据数值比较,不管花色
// 这里我们认为 null 是最小的
@Override
public int compareTo(Card o)
if(o==null)
return 1;
return rank-o.rank;
public static void main(String[] args)
Card p = new Card(1, "♠");
Card q = new Card(2, "♠");
Card o = new Card(1, "♠");
if(p.compareTo(o)<0)
System.out.println('p'+"<"+'o');
else if(p.compareTo(o)==0)
System.out.println('p'+"=="+'o');
else
System.out.println('p'+">"+'o');
(4)基于Comparator比较器的比较
光有Comparable接口,不足以比较所有的对象。因为不是所有类都实现了Comparable接口。比如java.util.List和java.util.ArrayList与Comparable接口之间就没有关系。这时候就需要使用比较器。
1.用户自定义比较器类,实现Comparator接口
Comparator是JDK提供的泛型的比较接口类,源码实现具体如下:
public interface Comparator<T>
int compare(T o1, T o2);
2.覆写Comparator中的compare方法
import java.util.Comparator;
class Card
public int rank; // 数值
public String suit; // 花色
public Card(int rank, String suit)
this.rank = rank;
this.suit = suit;
class CardComparator implements Comparator<Card>
// 根据数值比较,不管花色
// 这里我们认为 null 是最小的
@Override
public int compare(Card o1, Card o2)
if (o1 == o2)
return 0;
if(o1 == null)
return -1;
if(o2 == null)
return 1;
return o1.rank - o2.rank;
public static void main(String[] args)
Card p = new Card(1, "♠");
Card q = new Card(2, "♠");
Card o = new Card(1, "♠");
// 定义比较器对象
CardComparator cmptor = new CardComparator();
// 使用比较器对象进行比较
System.out.println(cmptor.compare(p, o)); // == 0,表示牌相等
System.out.println(cmptor.compare(p, q)); // < 0,表示 p 比较小
System.out.println(cmptor.compare(q, p)); // > 0,表示 q 比较大
(5)三种比较方式对比
覆写的方法 | 说明 |
Object.equals | 因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与 否 |
Comparable.compareTo | 需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于 内部顺序 |
Comparator.compare | 需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性 强 |
三、PriorityQueue的比较方式
集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了:
Comparble和Comparator两种方式。
1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法。
2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法。
使用PriorityQueue创建大小堆,解决TOPK问题:
//使用比较器创建小根堆
class LessIntComp implements Comparator<Integer>
@Override
public int compare(Integer o1, Integer o2)
return o1 - o2;
//使用比较器创建大根堆
class GreaterIntComp implements Comparator<Integer>
@Override
public int compare(Integer o1, Integer o2)
return o2 - o1;
public class TestDemo<E>
//求最小的K个数,通过比较器创建大根堆
public static int[] smallestK(int[] array, int k)
if (k <= 0)
return new int[k];
GreaterIntComp greaterCmp = new GreaterIntComp();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(greaterCmp);
//先将前K个元素,创建大根堆
for (int i = 0; i < k; i++)
maxHeap.offer(array[i]);
//从第K+1个元素开始,每次和堆顶元素比较
for (int i = k; i < array.length; i++)
int top = maxHeap.peek();
if (array[i] < top)
maxHeap.poll();
maxHeap.offer(array[i]);
//取出前K个
int[] ret = new int[k];
for (int i = 0; i < k; i++)
int val = maxHeap.poll();
ret[i] = val;
return ret;
public static void main (String[]args)
int[] array = 4, 1, 9, 2, 8, 0, 7, 3, 6, 5;
int[] ret = smallestK(array, 3);
System.out.println(Arrays.toString(ret));
Java 常用类库 之 比较类 Comparable
http://www.verejava.com/?id=169930999133100
/**
知识点: 比较类 Comparable
题目: 将某班学生按数学成绩从小到大排序
思路:
1. 抽象出类:
1.1 班级(ClassSet)
1.2 学生(Student)
2. 找出类关系:
2.1 学生 属于 班级 Student -> ClassSet(多对1)
3. 找出类属性:
3.1 ClassSet(班级名称,班级人数)
3.2 Student(学生名称,数学成绩)
4. 找出类方法:
4.1 学生添加到班级 ClassSet{addStudent(Student s)}
4.2 学生成绩从小到大排序 ClassSet{sortByScore()}
*/
import java.util.Arrays;
public class TestComparable
{
public static void main(String[] args)
{
//实例化4G班级
ClassSet c=new ClassSet("4G",4);
//添加学生
c.addStudent(new Student("李明",90));
c.addStudent(new Student("李浩",80));
c.addStudent(new Student("王涛",95));
c.addStudent(new Student("张胜",70));
//获得4G班级学生数组集合
Student[] students=c.getStudents();
//输出学生信息
for(Student s:students)
{
if(s!=null)
System.out.println(s.getName()+","+s.getMathScore());
}
System.out.println("
根据学生成绩排序");
//c.sortByBuble();
//Arrays.sort(students);
c.sortByMerge();
for(Student s:students)
{
if(s!=null)
System.out.println(s.getName()+","+s.getMathScore());
}
}
}
class ClassSet
{
private String className;//班级名称
private int maxSize;//班级学生人数
private int currentSize;//当前多少学生
private Student[] students;//所有学生的数组
public ClassSet(String className,int maxSize)
{
this.className=className;
this.maxSize=maxSize;
students=new Student[maxSize];
}
public Student[] getStudents()
{
return this.students;
}
/**
添加学生
*/
public void addStudent(Student s)
{
for(int i=0;i<students.length;i++)
{
if(students[i]==null)
{
students[i]=s;
currentSize++;
break;
}
}
}
/**
按照学生的数学成绩冒泡排序从小到大排序
*/
public Student[] sortByBuble()
{
for(int i=0;i<currentSize-1;i++)
{
for(int j=0;j<currentSize-i-1;j++)
{
Student s=students[j];
if(students[j].getMathScore()>students[j+1].getMathScore())
{
students[j]=students[j+1];
students[j+1]=s;
}
}
}
return this.students;
}
public void sortByMerge()
{
//创建一个临时数组存放分区元素
Comparable[] tempArray=students.clone();
merge_sort(students,tempArray,0,students.length);
}
private void merge_sort(Comparable[] array,Comparable[] tempArray, int first, int last) {
if(first+1<last)
{
int mid=(first+last)/2;
// 对左半部份排序
merge_sort(array,tempArray,first,mid);
// 对有半部分排序
merge_sort(array,tempArray,mid,last);
// 合并到一个临时数组,再拷贝到array中
merge(array,tempArray,first,mid,last);
}
}
private void merge(Comparable[] array,Comparable[] tempArray, int first, int mid,int last) {
int beginLeft=first;
int beginRight=mid;
int k=first;
while((beginLeft<mid)&&(beginRight<last)){
if(array[beginLeft].compareTo(array[beginRight])<0){
tempArray[k]=array[beginLeft];
beginLeft++;
}else{
tempArray[k]=array[beginRight];
beginRight++;
}
k++;
}
while(beginLeft<mid){
tempArray[k++]=array[beginLeft++];
}
while(beginRight<last){
tempArray[k++]=array[beginRight++];
}
for(int i=first;i<last;i++){
array[i]=tempArray[i];
}
}
}
class Student implements Comparable
{
private String name;//学生姓名
private int mathScore;//数学成绩
public Student(String name,int mathScore)
{
this.name=name;
this.mathScore=mathScore;
}
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name=name;
}
public int getMathScore()
{
return this.mathScore;
}
public void setMathScore(int mathScore)
{
this.mathScore=mathScore;
}
/**
实现Comparable 接口要复写 compareTo(T o) 方法
如果从小到大排序
大于 则返回 1
小于 则返回 -1
等于 则返回 0
如果从大到小排序
大于 则返回 -1
小于 则返回 1
等于 则返回 0
*/
public int compareTo(Object obj)
{
if(obj instanceof Student)
{
Student s=(Student)obj;
if(this.mathScore>s.getMathScore())
return 1;
if(this.mathScore<s.getMathScore())
return -1;
}
return 0;
}
}
http://www.verejava.com/?id=169930999133100
以上是关于数据结构Java版对象的比较之Comparable与Comparator比较器的主要内容,如果未能解决你的问题,请参考以下文章