文章目录
一,关于对象值相等的比较
1, == VS equals
- p == q 表示的是 p 和 q 两个引用指向同一个对象
- p.equals(q) 表示 p 指向的对象 和 q 指向的对象是否是值语义相等的
2,代码示例
覆写equals前
class Card { //扑克牌
public String rank; //点数
public String suit; //花色
public Card(String rank, String suit) {
this.rank = rank;
this.suit = suit;
}
}
public class TestCompare {
public static void main(String[] args) {
Card p = new Card("3","♠");
Card q = new Card("3","♠");
Card o = p;
System.out.println(o == p); //测试 == 比较身份
System.out.println(p == q);
System.out.println("===============================");
System.out.println(p.equals(o)); //测试比较内容
System.out.println(p.equals(q)); //没有重写的话,使用的是Object中的原始的equals方法,相当于依旧比较的是身份
}
}
运行结果:
覆写equals后
class Card {
public String rank; //点数
public String suit; //花色
public Card(String rank, String suit) {
this.rank = rank;
this.suit = suit;
}
@Override
public boolean equals(Object obj) {
//按照值比较this和obj
// 1,自己与自己比较
if(this == obj){
return true;
}
//2,obj为null的情况
if(obj == null){
return false;
}
//3,obj类型不是当前card类型
if(! (obj instanceof Card) ){
return false;
}
//4,真正的比较内容
Card other = (Card)obj;
return this.rank.equals(other.rank) && this.suit.equals(other.suit);
}
}
public class TestCompare {
public static void main(String[] args) {
Card p = new Card("3","♠");
Card q = new Card("3","♠");
Card o = p;
System.out.println(o == p); //测试 == 比较身份
System.out.println(p == q);
System.out.println("===============================");
System.out.println(p.equals(o)); //测试比较内容
System.out.println(p.equals(q)); //重写后
}
}
注意: 一般覆写 equals 的套路就是上面演示的
- 如果指向同一个对象,返回 true
- 如果传入的为 null,返回 false
- 如果传入的对象类型不是 Card,返回 false
- 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌
- 注意下调用其他引用类型的比较也需要 equals,例如这里的 suit 的比较
二,关于对象值大于、等于、小于的比较-基于自然顺序
1,认识 Comparable
public interface Comparable<E> {
// 返回值:
// < 0: 表示 this 指向的对象小于 o 指向的对象
// == 0: 表示 this 指向的对象等于 o 指向的对象
// > 0: 表示 this 指向的对象等于 o 指向的对象
int compareTo(E o);
}
2,代码示例
package java15_20200510;
class Card implements Comparable<Card>{
public String rank; //点数
public String suit; //花色
public Card(String rank, String suit) {
this.rank = rank;
this.suit = suit;
}
@Override
public int compareTo( Card o) {
//如果this比o小,返回一个小于0的整数
//如果this比o大,返回一个大于0的整数
//如果this == o,返回0
if(o == null){
//一般我们就认为this比o大,null比较小
return 1;
}
//点数取值2-10. JQKA
int rank1 = this.getValue();
int rank2 = o.getValue();
return rank1-rank2;
}
public int getValue(){
//通过这个方法把String类型变为整数点数
int value = 0;
if("j".equals(rank)){
value = 10;
} else if("Q".equals(rank)){
value = 11;
} else if("k".equals(rank)){
value = 12;
} else if("A".equals(rank)){
value = 14;
} else {
value = Integer.parseInt(rank);
}
return value;
}
}
public class TestCompare {
public static void main(String[] args) {
Card p = new Card("3","♠");
Card q = new Card("3","♠");
Card o = p;
System.out.println(p.compareTo(null));
System.out.println(p.compareTo(q));
}
}
运行结果:
三, 关于对象值大于、等于、小于的比较-基于比较器
1, 认识 Comparator
public interface Comparator<T> {
// 返回值:
// < 0: 表示 o1 指向的对象小于 o2 指向的对象
// == 0: 表示 o1 指向的对象等于 o2 指向的对象
// > 0: 表示 o1 指向的对象等于 o2 指向的对象
int compare(T o1, T o2){
//Do
}
}
2,代码示例
import java.util.Comparator;
class Card {
public String rank; //点数
public String suit; //花色
public Card(String rank, String suit) {
this.rank = rank;
this.suit = suit;
}
public int getValue(){
//通过这个方法把String类型变为整数点数
int value = 0;
if("j".equals(rank)){
value = 10;
} else if("Q".equals(rank)){
value = 11;
} else if("k".equals(rank)){
value = 12;
} else if("A".equals(rank)){
value = 14;
} else {
value = Integer.parseInt(rank);
}
return value;
}
}
class CarComparator implements Comparator<Card> {
@Override
public int compare(Card o1, Card o2) {
if(o1 == o2){
return 0;
}
if(o1 == null){
return -1;
}
if(o2 == null){
return 1;
}
int result1 = o1.getValue();
int result2 = o2.getValue();
return result1-result2;
}
}
public class TestCompare {
public static void main(String[] args) {
Card p = new Card("3","♠");
Card q = new Card("3","♠");
Card o = p;
CarComparator comparator = new CarComparator();
System.out.println(comparator.compare(p,q));
System.out.println(comparator.compare(p,null));
System.out.println(comparator.compare(null,q));
}
}
运行结果:
四,比较
五,和 java 集合框架的配合
- 使用 contains 类似的方法,内部基本在调用元素的 equals 方法,所以要求元素覆写过 equals 方法
- 使用 HashMap,key 的比较内部会调用 equals 方法,所以要求元素覆写过 equals 方法
- 使用排序相关方法,内部需要进行比较,所以或者选择实现 Comparable 或者传入一个 Comparator
- 使用 TreeMap,key 需要进行大小比较,所以或者选择实现 Comparable 或者传入一个 Comparator
- 其他规则以此类推
六,注意事项
1,使用Comparable接口的时候,最好指定泛型参数.编译器自动的完成类型校验工作.如果不写泛型参数,默认的compareTo方法的参数类型就是Object类型.需要程序猿手动进行类型转换.
2,使用Comparable的时候,你必须让要比较的类实现Comparable接口. (需要修改这个类的代码)
3,使用Comparator的时候,你是重新创建一个新的类实现Comparator接口,不需要修改待比较类的代码
问题:为啥有了Comparable还需要有一个Comparato呢?
1,使用Comparator的时候必须要修改带比较类的代码,实际开发中不是所有的类都能修改源码(这个类是库或者其它组提供的)
2.Comparable只能定义一种比较规则,Comparator可以定义多种比较规则