在Java中,基本类型的对象可以直接比较大小。
(<,>,>=,<=,==,!=)
==运算符比较:
基本数据类型,比较值是否相同
引用类型,比较引用变量的首地址是否相同
equals 有两种判断方式,但是都是建立在引用类型上的比较
1.当我们的子类没有重写equals 时,我们调用的时Object 的equals方法,只能判断两个引用类型的地址是否相同;
2.当我们的子类重写equals 时,可以判断的是内容是否相等,这里判断的规则我们自己写。(我自己这么理解的)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) { // 自己和自己比较,如果相等返回true if (this == o) { return true; } //o如果是null对象,或者o不是Card的子类 if (o == null || !(o instanceof Card)) { return false; } //注意基本类型可以直接比较,但引用类型最好调用其equal方法 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只能按照相等进行比较,不能按照大于、小于的方式进行比较。
equalsgnoreCase 比较的是内容并且忽略大小写。
Comparble是JDK提供的泛型的比较接口类,源码实现具体如下:
public interface Comparable
{ public int compareTo(T o);
}
该接口只存在一个public int compareTo(T o);
方法,该方法表示所在的对象和o对象进行比较,返回值分三种:
1: 表示当前对象大于o对象
0: 表示当前对象等于o对象
-1: 表示当前对象小于o对象
对用用户自定义类型,如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法
举个栗子:
需求: 在优先级队列中存储对象学生,每个学生有id,name,age三个属性,并且使优先级队列每次按照学生的id从小到大取出。
代码示例:
Student类: 当前类实现了Comparable接口
,即当前类提供了默认的比较方法。实现接口,创建自定义类 public class Student implements Comparable{ private int id; private String name; private int age; public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } //重写compareTo方法 @Override public int compareTo(Object o) { Student o1 = (Student)o; return this.id - o1.id; } }
如果使优先级队列按照学生id从大到小取出呢?我们很快就会想到修改Student类的compareTo方法,使return o1.id - this.id;,这样当然可以实现我们的新需求。但是有很多时候类的compareTo方法是不能修改的,比如JDK给我们提供的源代码,在不修改compareTo方法的前提下实现需求,只能用Comparator比较器了。
Comparator接口
public interface Comparator
{ int compare(T o1, T o2);
}
该接口中提供了int compare(T o1, T o2)方法,该方法需要参数是两个待比较的对象
返回结果是int类型:
1: 表示o1对象大于o2对象
0: 表示o1对象等于o2对象
-1: 表名o1对象小于o2对象
覆写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 {
// 根据数值比较,不管花色
// 这里我们认为 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 比较大
}
}
注意:Comparator是java.util 包中的泛型接口类,使用时必须导入对应的包。
三种方式的比较
覆写的方法 | 说明 |
Object.equals | 因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与 否 |
Comparable.compareTo | 需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于 内部顺序 |
Comparator.compare | 需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性 强 |