对象的比较

简介: 本篇文章是对Java中一些常见的比较的总结,在涉及到比较方面,有元素的比较与对象的比较,下边博主来带领大家一起了解这些比较方式。

1.基本类型的比较


在Java中,常见的基本类型比如int、char、boolean类型都可以直接比较。


代码示例:


public class Demo {
    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);
    }
}
//
false
true
false
false
true
false
false
true
Process finished with exit code 0

2.对象的比较


Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较,但可以用==来比较,因为对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equals方法,而 == 默认情况下调用的就是equals方法,但该方法比较的是引用对象的地址,在有些情况下需要比较的是对象中的内容,下边我们就通过扑克牌的比较例子来具体说明这个问题。


// Object中equals的实现,可以看到:直接比较的是两个引用变量的地址
public boolean equals(Object obj) { 
  return (this == obj); 
}


2.1 重写基类的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) {
        //和自己比较
        if (this == o) return true;
        //如果为null或类型不匹配
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        //数字和花色都相同才返回true
        return rank == card.rank && Objects.equals(suit, card.suit);
    }
    @Override
    public int hashCode() {
        return Objects.hash(rank, suit);
    }
}


注意:


  • 如果指向同一个对象,返回 true
  • 如果传入的为 null,返回 false
  • 如果传入的对象类型不是 Card,返回 false
  • 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌
  • 存在的缺陷:
  • equals只能按照相等进行比较,不能按照大于、小于的方式进行比较。

2.2 实现Comparble接口


Comparble是JDK提供的泛型的比较接口类,源码实现具体如下:


public interface Comparable<E> { 
  // 返回值: 
  // < 0: 表示 this 指向的对象小于 o 指向的对象 
  // == 0: 表示 this 指向的对象等于 o 指向的对象 
  // > 0: 表示 this 指向的对象大于 o 指向的对象 
  int compareTo(E o); 
}


对用用户自定义类型,如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法。


public class Card implements Comparable<Card>{
    public int rank;//数字
    public String suit;//花色
    public Card(int rank,String suit) {
        this.rank=rank;
        this.suit=suit;
    }
    //根据数值比较
    @Override
    public int compareTo(Card o) {
        return this.rank-o.rank;
    }
    public static void main(String[] args) {
        Card c1=new Card(1,"♠");
        Card c2=new Card(2,"♣");
        System.out.println(c1.compareTo(c2));
    }
}
//
-1
Process finished with exit code 0


存在的缺陷:

对类的侵入性较大,让类实现Comparble接口重写compareTo方法后就指定了比较的方式(指定了用于比较的属性),若对象想要通过其他的属性来进行比较时就无法实现了。


2.3 比较器(实现Comparator接口)


通过调用下边这个接口就可以实现对象中指定属性的比较,这样就将需要比较的类的属性从原类中抽取出来,对类的侵入性大大减小。


用户自定义比较器类,实现Comparator接口

public interface Comparator<T> { 
  // 返回值: 
  // < 0: 表示 o1 指向的对象小于 o2 指向的对象 
  // == 0: 表示 o1 指向的对象等于 o2 指向的对象 
  // > 0: 表示 o1 指向的对象等于 o2 指向的对象 
  int compare(T o1, T o2); 
}


覆写Comparator中的compare方法

public class Card {
    public int rank;//数字
    public String suit;//花色
    public Card(int rank,String suit) {
        this.rank=rank;
        this.suit=suit;
    }
    static class RankComparator implements Comparator<Card> {
        @Override
        public int compare(Card o1, Card o2) {
            return o1.rank-o2.rank;
        }
    }
    static class SuitComparator implements Comparator<Card> {
        @Override
        public int compare(Card o1, Card o2) {
            return o1.suit.compareTo(o2.suit);
        }
    }
    public static void main(String[] args) {
        Card c1=new Card(1,"♠");
        Card c2=new Card(2,"♣");
        RankComparator rankComparator = new RankComparator();
        SuitComparator suitComparator = new SuitComparator();
        System.out.println(rankComparator.compare(c1,c2));
        System.out.println(suitComparator.compare(c1,c2));
    }
}
//
-1
-3
Process finished with exit code 0


2.4 总结

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

3.集合框架中PriorityQueue的比较


集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了:


Comparble和Comparator两种方式。


  1. 1.Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法
  2. 2.用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法。


JDK中PriorityQueue的实现:


public class PriorityQueue<E> extends AbstractQueue<E>
        implements java.io.Serializable {
// ... 
// 默认容量 
    private static fifinal int DEFAULT_INITIAL_CAPACITY = 11;
    // 内部定义的比较器对象,用来接收用户实例化PriorityQueue对象时提供的比较器对象 
    private fifinal Comparator<? super E> comparator;
    // 用户如果没有提供比较器对象,使用默认的内部比较,将comparator置为null 
    public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }
    // 如果用户提供了比较器,采用用户提供的比较器进行比较 
    public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed, 
// but continues for 1.5 compatibility 
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }
    // ... 
// 向上调整: 
// 如果用户没有提供比较器对象,采用Comparable进行比较 
// 否则使用用户提供的比较器对象进行比较 
    private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }
    // 使用Comparable 
    @SuppressWarnings("unchecked")
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }
    // 使用用户提供的比较器对象进行比较 
    @SuppressWarnings("unchecked")
    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }
}
相关文章
|
6月前
|
C++
C++中的对象
C++中的对象
54 2
|
6月前
|
测试技术 索引
v-for 与对象
v-for 与对象
|
前端开发
67 # 对象的处理
67 # 对象的处理
34 0
|
存储 程序员 编译器
C++都有对象了,你还没有吗?
C++都有对象了,你还没有吗?
83 0
|
Java 开发者 容器
你有对象吗?
你有对象吗?
107 0
|
存储 JSON Java
谈“对象“
谈“对象“
|
存储 编译器 C语言
我现在必须new一个对象!!!
C++内存管理,手动开辟空间,我现在必须new一个对象!!!
89 0
我现在必须new一个对象!!!
|
编译器 C语言
对象的比较
对象的比较
68 0
对象的比较