Java对象的比较【数据结构】

x33g5p2x  于2021-10-25 转载在 Java  
字(3.3k)|赞(0)|评价(0)|浏览(380)

对象值相等的比较

== & equals

== 是用来比较对象身份的,而 equals 一般是用来比较对象的内容的
但equals 若没有手动重写,默认执行的就是 object 版本中的 equals,比较规则也是在比较身份

举例:

class Card{
    private String rank;    //点数
    private String suit;    //花色

    public Card(String rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }
}

1.== 比较:

public static void main(String[] args) {
    Card s1 = new Card("5","♠");
    Card s2 = new Card("5","♠");
    Card s3 = s1;
    System.out.print("s1 == s3: ");
    System.out.println(s1 == s3);
    System.out.print("s1 == s2: ");
    System.out.println(s1 == s2);
}

输出结果

对于用户实现自定义类型,都默认继承于 Object 类,而 Object 类中提供了 equals 方法,== 默认情况下调用的就是 equals 方法,比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址,因此 s1==s3 是 true,s1 == s2 是false

2.equals比较:

public static void main(String[] args) {
    Card s1 = new Card("5","♠");
    Card s2 = new Card("5","♠");
    Card s3 = s1;
    System.out.print("s1.equals(s3): ");
    System.out.println(s1.equals(s3));
    System.out.print("s1.equals(s2): ");
    System.out.println(s1.equals(s2));
}

输出结果:

一般来说 equals 是比较对象内容的,但若没有手动重写 equals 方法,则会使用 object 版本中的 equals 方法,默认比较规则是:比较对象的身份,没有比较对象的内容

手动重写 equals 方法:

@Override
public boolean equals(Object obj) {
    //按照值比较 this 和 obj
    //1.自己和自己比
    if(this == obj){
        return true;
    }
    //2.obj 为null,结果为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);
}

此时再调用 equals 方法,输出结果:

重写 equals:

  • 若指向同一个对象,返回 true
  • 传入的参数为 null,结果为 null
  • 如果传入的对象类型不匹配,返回 false
  • 最后才是比较内容

**缺点:**equals 只能比较相等,不能比较大小

对象大小的比较

基于 Comparable 接口类

使用 Comparable 接口时,最好指定泛型参数,这样编译器就会自动的完成类型校验工作
若不写泛型参数,默认的 compareTo 方法的参数类型就是 Object 类型,此时需要程序猿手动实现类型转换

对于用户自定义类型,若想按照大小来进行比较:在定义类时,实现 Comparble 接口,在类中重写compareTo方法即可

class Card implements Comparable<Card>{
    private String rank;    //点数
    private 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 > null
            return 1;
        }
        // 点数取值 2-10,J Q K A
        int rank1 = this.getValue();
        int rank2 = o.getValue();
        return rank1 - rank2;
    }
    private int getValue(){
        // 把 String 类型的 rank 变成数字点数
        int value = 0;
        if("J".equals(rank)){
            value = 11;
        }
        else if("Q".equals(rank)){
            value = 12;
        }
        else if("K".equals(rank)){
            value = 13;
        }
        else if("A".equals(rank)){
            value = 14;
        }
        else {
            value = Integer.parseInt(rank);
        }
        return value;
    }
}

输出结果:

public static void main(String[] args) {
    Card s1 = new Card("5","♠");
    Card s2 = new Card("5","♣");
    Card s3 = s1;
    System.out.println(s1.compareTo(s2));
    System.out.println(s1.compareTo(s3));
}

基于 Comparator 比较器

使用方法和 Comparable 一样,先实现 Comparator 接口,再重写 Comparator 中的 compare 方法(需要修改这个类的代码)

class CardComparator 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 value1 = o1.getValue();
        int value2 = o2.getValue();
        return value1 - value2;
    }
}

输出结果:

public static void main(String[] args) {
    Card s1 = new Card("5","♠");
    Card s2 = new Card("11","♣");

    CardComparator comparator = new CardComparator();
    System.out.println(comparator.compare(s1,s2));
}

使用 Comparable 的时候,必须让要待比较类来实现 Comparable 接口,需要修改这个类的代码 (耦合性更强)
而使用 Comparator 的时候,是重新创建一个类来实现 Comparator 接口,不需要修改待比较类的代码

三种比较方式总结

方法:说明
Object.equals因为 Object 是所有子类的父类,所以直接重写即可,但只能比较相等
Comparable.compareTo需要手动实现接口,侵入性较强,但一旦实现,每次用该类都有顺序,属于内部顺序
Comparator.compare需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强

相关文章