深入完整的带你了解java对象的比较

深入完整的带你了解java对象的比较_第1张图片

 

目录

元素的比较

1.基本类型的比较

2.对象比较的问题

1.运行结果

2.疑问

3.原因

对象的比较

1.覆写基类的equals 

2.基于Comparble接口类的比较

3.基于比较器比较

4.三种方式对比 


元素的比较

1.基本类型的比较

在Java 中,基本类型的对象可以直接比较大小。

 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); 
    } 
} 

2.对象比较的问题

class Card { 
       public int rank;    // 数值                   
       public String suit; // 花色 
       public Card(int rank, String suit) {
           this.rank = rank; 
           this.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指向的是同一个对象 
       } 
 } 

1.运行结果

c1、c2和c3分别是Card类型的引用变量,上述代码在比较编译时:

c1 > c2 编译失败

c1== c2 编译成功

c1 < c2 编译失败

2.疑问

从编译结果可以看出,Java 中引用类型的变量不能直接按照 > 或者 < 方式进行比较。 那为什么==可以比较?

3.原因

因为:对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法 ,但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址 ,但有些情况下该种比较就不符合题意。

下面代码Object中equal的实现 ,可以看到 :直接比较的是两个引用变量的地址  

// Object中equal的实现 ,可以看到 :直接比较的是两个引用变量的地址 

public boolean equals(Object obj) { 

    return (this == obj); 
}

对象的比较

有些情况下,需要比较的是对象中的内容,比如:向优先级队列中插入某个对象时,需要对按照对象中内容来调整课

堆,那该如何处理呢?

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; 

       } 
       
       // 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只能按照相等进行比较,不能按照大于、小于的方式进行比较。

2.基于Comparble接口类的比较

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

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

   // 返回值: 
   // < 0:  表示 this 指向的对象小于 o 指向的对象 
   // == 0: 表示 this 指向的对象等于 o 指向的对象    // > 0:  表示 this 指向的对象大于 o 指向的对象   

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

public class Card implements Comparable { 

    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, "♠"); 

       System.out.println(p.compareTo(o));     // == 0 ,表示牌相等 

       System.out.println(p.compareTo(q));     // < 0 ,表示  p 比较小 

       System.out.println(q.compareTo(p));     // > 0 ,表示 q 比较大 

   } 
}

Compareble是java.lang 中的接口类,可以直接使用。

3.基于比较器比较

按照比较器方式进行比较,具体步骤如下:

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


       public interface Comparator { 

          // 返回值: 

          // < 0: 表示 o1 指向的对象小于 o2 指向的对象 

          // == 0: 表示 o1 指向的对象等于 o2 指向的对象 

          // > 0: 表示 o1 指向的对象等于 o2 指向的对象 

          int compare(T o1, T o2); 

      }                                                                            

  注意:区分Comparable和Comparator。 

  •    覆写Comparator中的compare方法                                             
import j ava.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 包中的泛型接口类,使用时必须导入对应的包。

4.三种方式对比 

覆写的方法                说明

Object.equals                因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与就否 

Comparable.compareTo                需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序

Comparator.compare                需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强

你可能感兴趣的:(学习笔记,java,算法,开发语言)