Java 比较(==, equals, compareTo, compare)

在Java中,有 ==, equals(), compareTo(), compare() 等方法可以比较两个值或对象,比较容易混淆。画了个简单的思维导图总结一下

Paste_Image.png

Java Compares

我经常记不住Java中的各种比较方法,为什么设计者要弄出这么多种比较?

设计源于生活,如果我们先想一想现实世界中一般会如何做比较,也许会对理解Java的设计有所帮助吧。那么,在现实世界中,我们是怎么进行比较的呢?

假如给定两个物体,如果要对二者作比较的话,一般我们会先问:

有可比性吗?

如果没有可比性,那就无需再谈。但是从广义上讲,其实任何东西都可以互相比较的,所以可比性是有个限定范围的,即如果要两者可比,那就得限定规则范围,这样也就可以理解 Java 中 compareTo 了:

**在 Java 中 compareTo() 可以比较的两个对象的类必须都实现 Comparable 接口。

compare() 则是 Comparator 接口定义的方法。**

如果有可比性,又会问:

为什么比?
比啥?
怎么比?

让我们挨个来看:

为什么比?
因为要根据比较的结果来做决策或决定,具体就不展开了,各种应用情况不一样。比如:公司的绩效考核评优,运动会比赛夺冠等等。

**在 Java 中 equals()的比较结果是 boolean 类型,如果是 true 则表示二者相同的时候do something, 否则不同的时候 do else things,

而compareTo() ,compare() 的比较结果是:0表示相同,正负数表示不同,至于是正负多少,看所不同的字符在编码表中的差距。至于为啥要这么设计,我初步的想法是,根据不同的返回值的大小,可以用于排序,但具体还没想通(以后补上)

比啥?
这个要比的方面真是很多,让我们简单举几个例子:

1。小朋友开始学数学的时候,会被问到“2”和“3”哪个大啊? 这里比较的是简单的数值,在Java中多设计为基本数据类型。

在 Java 中,用 == 来比较基本数据类型(Primitive Type),直接比较的是值(Value)是否相等。
equals() 和 compareTo() 都是方法,不适用于基本数据类型。

2。你一定听过也许是亲自体会过,“你看人家老王家的某某,这次又比你考的好。。。”,这比的啥?成绩,很直观的数据比较。类似还有,你和你弟弟一般高吗?量下身高数据即可。

这里也是数值,和前面的例子稍不同的是,身高是老王家的某某的一个指标,在 Java 中一般把老王家的某某,定义为某个类比如Person类的一个对象,身高则是他的一个属性。因为对象的属性通常比较多,为了简化问题,在这里让我们做个假设:两个对象是同一个类的对象,只有一个属性。这种情况下如何判断这两个对象是否相同呢?(比如是不是同一个人(Person)?)

在 Java 中,对于引用类型的对象,可以用重写Object类的equals()方法比较两个对象的属性值,也是看值(Value)是否相等。compareTo()似乎也可以用,不过应该不太常用在这种情况

3。你老板这天过来找你:小王,你比较下两个品牌电脑上半年的销售情况,我发了两个电子清单给你,下班前给我个报告。“ 这会儿不太好直接进行数据比较了,咋办?你准备写了Java程序来干这活,不然你今晚就得加班了。

这种情况在 Java 中,这两份文档就得作为引用类型来比较了,equals(), compareTo(),compare() 就派上用场了。== 也可以用,但一般不直接使用,容易出问题。

怎么比
写程序前,你先大概浏览了一下两个文件,突然发现怎么内容都差不多嘛,再仔细看看,分明就是同一份清单,可能老板复制了同一份。

在 Java 中,equals() 和 compareTo(), 包括compare()的实现, 在比较两个对象的时候,都会先做一个判断,判断二者是否是同一对象。这里就用到了 == ,比较的是这两个引用存的是否是同一地址

public boolean equals (Object x){
  if(this == x) return true;
  ....
}

可能还有一种情况,你发现,咦,怎么有一份文件是空的?这没法比了。

在 Java 中,equals()方法 x.equals(null) 返回的是false。 而 x.compareTo(null) 返回的则是NullPointerException,这个得注意了。

不管怎样,后来终于可以认真比较了,你可能要比较很多方面:

  • 各电脑品牌的销售地域是否相同
  • 各地域销量是否相同
  • 如何按价格排序
  • 如何按销量排序
  • ...

那么你是要用 equals(), 还是compareTo(), 亦或是compare()?

我个人的理解:

1。如果只是需要在某个方法中简单的比较属性值是否相等,用equals()

在 Java 中,equals() 是 Object 类的方法,有默认实现方法,返回值是boolean。(比如比较 两个String,如果长度不等,返回false, 否则比较各个字符,如均同则返回true)。

实际应用中,比如Date对象,Java默认的实现方式是比较getTime()毫秒级的,如果你的程序需要比较年月日,这时候可重写equals方法。

public boolean equals(Object x){
if (this == x) return true;
if (x == null) return false;
if (this.getClass() != x.getClass()) return false; // Not sure what if inheritance?
Date that = (Date) x;
if (this.day !=that.day) return false;
if(this.month!=that.month) return false;
if (this.year!=that.year) return false;
return true;
}


2。如果需要进行排序,可结合compareTo() 和 compare() 方法。

> compareTo():  对象须实现 Comparable 接口 (必须有可比性)

> compare() : Comparator 接口中定义的方法,具体实现时可调用compareTo() 方法。

二者返回值类似,0 表示相同,负数表示排在前,正数表示排在后。

都是排序,有什么特别的区别吗?

> compareTo(): Java 称之为Lexicographically 排序,以String对象为例,从源码可看到,比较的是某一index上的字符的Unicode编码值。
- 每个index上的字符都相同且字符串长度相等,返回 0
- 某个index上的字符没有对应的另一字符串Index,返回 字符串长度差值
- 某个index上的字符有对应Index但是Unicode值不同,返回二者Unicode值的差值

很明显, compareTo() 使用比较局限,适合作为low level的底层调用。

> compare() 则可更灵活,比如按照产品的销售区域,价格,销量等多种方式来排序,则可在类中重写compare()方法,或使用匿名类实现该方法,便于以后的sort方法。

class XX {
public int compare(Product p1, Product p2){
return p1.price - p2.price;
}
}

// 匿名类
Collections.sort(list, new Comparator(){
@Override
public int compare(Product p1, Product p2) {
return p1.price - p2.price;
}
}


以上是我的一些粗浅的认识,关于比较这一块有时候的话还得再深入一下。

另外排序也是后续会重点学习的方面,毕竟最基本的算法就是排序算法了。

**如何理解 引用类型的 == 是指向同一个对象? **

我在简书上写了这篇文章,发表后,我分别分享了一份到博客上,一份到我的微信公众号上,
也就是说,我的博客和公众号上都各有一个link指向我的这篇简书文章。

博客和微信的地址类似于Java中的引用,都指向了同一个对象(简书)。所以此时二者可用==表示指向了同一对象。

### 参考文章
[==, .equals(), compareTo(), and compare()](http://www.cnblogs.com/CoolRandy/articles/3676695.html)

posted on 2017-04-16 11:09  不忘初心mao  阅读(542)  评论(0编辑  收藏  举报

导航