compareTo()与equals()的区别

131
在Java中测试String的相等性时,我一直使用equals()方法,因为它似乎是最自然的方法。毕竟,它的名称已经说明了其意图。然而,我的一位同事告诉我,他被教导使用compareTo() == 0而不是equals()。这让我感到很不自然(因为compareTo()用于提供排序而不是比较相等),甚至有点危险(因为compareTo() == 0并不一定意味着在所有情况下都相等,尽管我知道对于String是这样的)。
他不知道为什么要使用compareTo()而不是equals(),我也找不到任何原因。这真的只是个人口味问题吗?还是有任何真正的理由支持其中任意一种方法?

11
严格来说,在微观优化层面上,我们不应该过早地谈论,如果适当的话,.equalsIgnoreCase() 是最快的比较方法,否则.equals()是您想要的。 - user177800
4
这是一个古老的问题,但其中包含了我想要强调的一点: "compareTo() == 0并不一定意味着在所有情况下都相等"。这完全正确!这正是Java API规范中的短语“与相等一致”所指的意思,例如在Comparable类规范中。例如,String的比较方法与相等一致,但BigDecimal的比较方法与相等不一致。 - Stuart Marks
21个回答

118

它们的不同之处在于"foo".equals((String)null)会返回false,而"foo".compareTo((String)null) == 0会抛出一个空指针异常。因此,即使对于字符串,它们也并不总是可互换的。


6
我认为你还应该提到这一点:“equals”方法计算哈希码。虽然罕见,但两个不同的字符串的哈希码可能相同。但是,使用“compareTo()”方法时,它会逐个字符地检查字符串。所以在这种情况下,只有当它们的实际内容相等时,两个字符串才会返回true。 - Ashwin
34
你为什么认为equals方法会计算哈希码?你可以看到事实并非如此:http://www.docjar.com/html/api/java/lang/String.java.html(第1013行)。 - waxwing
3
你说得对。我曾认为equals和hashcode是相辅相成的(equals会检查两个对象是否具有相同的哈希码)。那么,如果您决定覆盖其中任何一个方法,为什么需要同时覆盖这两种方法呢? - Ashwin
3
当我们重写equals方法时需要同时重写hashcode方法,因为如果该类使用基于哈希的集合(包括HashMap、HashSet和Hashtable),那么如果不重写hashcode方法,这些集合将无法正常运作。 - varunthacker
5
很有必要,因为如果.equals返回true,则哈希码也应该相等。但是,如果哈希码相等,并不意味着.equals应该返回true。 - Alan
显示剩余3条评论

40

这两个方法的主要区别在于:

  1. equals可以接受任何对象作为参数,但是compareTo只能接受字符串。
  2. equals仅告诉你它们是否相等,而compareTo提供了关于字符串在字典顺序上的比较信息。

我查看了String类代码,发现compareTo和equals内部的算法基本相同。 我认为这只是个人口味问题,我同意你的观点-如果你只需要知道字符串是否相等,而不关心哪个字符串在字典顺序上排名更高,则应该使用equals


32

在比较相等性时,应该使用equals(),因为它能清晰地表达你的意图。

compareTo()还有一个缺点是它只适用于实现了Comparable接口的对象。

这适用于一般情况,而不仅仅是字符串。


20

compareTo 如果字符串长度不同,需要处理更多的工作。而 equals 只需要返回 false,而 compareTo 必须始终检查足够数量的字符以找到排序顺序。


12

在字符串上下文中:
compareTo: 按字典顺序比较两个字符串。
equals: 将此字符串与指定对象进行比较。

compareTo 通过比较两个字符串的字符(在相同索引处)并相应地返回一个整数(正数或负数)来进行比较。

String s1 = "ab";
String s2 = "ab";
String s3 = "qb";
s1.compareTo(s2); // is 0
s1.compareTo(s3); // is -16
s3.compareTo(s1); // is 16

10

compareTo() 不仅适用于字符串,还适用于任何其他对象,因为 compareTo<T> 接受一个通用参数 T。String 是实现了 Comparable 接口的类之一,通过实现 compareTo() 方法来实现的。(compareTo() 是 comparable 接口的方法) 因此,任何类都可以自由地实现 Comparable 接口。

但是,compareTo() 给出了对象的顺序,通常用于按升序或降序排序对象,而 equals() 只涉及相等性,并判断它们是否相等。


9

equals()compareTo()更高效。

compareTo和equals之间非常重要的一个区别:

"myString".compareTo(null);  //Throws java.lang.NullPointerException
"myString".equals(null);     //Returns false
equals() 方法检查两个对象是否相同并返回布尔值。 compareTo() 方法(来自接口Comparable)返回一个整数。它检查两个对象中哪一个是“小于”,“等于”或“大于”另一个。并不是所有的对象都可以进行逻辑排序,因此 compareTo() 方法并不总是有意义的。
请注意,equals() 方法并没有定义对象之间的顺序,而 compareTo() 方法则有。
现在我建议您查看两种方法的源代码,以得出equals() 方法比涉及一些数学计算的compareTo() 方法更可取的结论。

6
似乎这两种方法基本上都是做同样的事情,但compareTo()方法需要输入一个字符串,而不是一个对象,并在普通equals()方法之上增加了一些额外的功能。如果你只关心相等性,则equals()方法是最好的选择,因为下一个查看您代码的程序员更容易理解。除非您正在循环处理大量项目,否则两个不同函数之间的时间差异不应该有任何影响。当您需要知道集合中字符串的顺序或需要知道以相同字符序列开头的字符串之间的长度差异时,compareTo()非常有用。
来源: http://java.sun.com/javase/6/docs/api/java/lang/String.html

5

equals()应该是这个问题的首选方法。

通过查看java.lang.String on grepcodeequals()compareTo()的实现,我们可以轻松地看出,如果我们只关心两个字符串的相等性,则equals()更好:

equals()

1012  public boolean equals(Object anObject) {
1013 if (this == anObject) {
1014 return true;
1015 }
1016 if (anObject instanceof String) {
1017 String anotherString = (String)anObject;
1018 int n = count;
1019 if (n == anotherString.count) {
1020 char v1[] = value;
1021 char v2[] = anotherString.value;
1022 int i = offset;
1023 int j = anotherString.offset;
1024 while (n-- != 0) {
1025 if (v1[i++] != v2[j++])
1026 return false;
1027 }
1028 return true;
1029 }
1030 }
1031 return false;
1032 }
这是一个方法,用于比较两个对象是否相等。如果它们指向同一对象,则返回true。否则,如果另一个对象是字符串且与此字符串具有相同的长度和字符,则返回true。否则返回false。

compareTo()

1174  public int compareTo(String anotherString) {
1175 int len1 = count;
1176 int len2 = anotherString.count;
1177 int n = Math.min(len1, len2);
1178 char v1[] = value;
1179 char v2[] = anotherString.value;
1180 int i = offset;
1181 int j = anotherString.offset;
1183 if (i == j) {
1184 int k = i;
1185 int lim = n + i;
1186 while (k < lim) {
1187 char c1 = v1[k];
1188 char c2 = v2[k];
1189 if (c1 != c2) {
1190 return c1 - c2;
1191 }
1192 k++;
1193 }
1194 } else {
1195 while (n-- != 0) {
1196 char c1 = v1[i++];
1197 char c2 = v2[j++];
1198 if (c1 != c2) {
1199 return c1 - c2;
1200 }
1201 }
1202 }
1203 return len1 - len2;
1204 }

这是一个用于字符串比较的方法,返回值为整型。其中涉及到了字符数组、数学运算符和循环等知识点。

当其中一个字符串是另一个字符串的前缀时,compareTo() 的性能会变差,因为它仍然需要确定词典序,而 equals() 则不再需要担心并立即返回 false。

我认为,我们应该按照它们的意图使用这两个方法:

  • 使用 equals() 来检查相等性,
  • 使用 compareTo() 来找到词汇顺序。

3

equals()函数用于判断两个字符串是否相等,返回boolean类型的值。 compareTo() 函数用于比较两个字符串对象的大小关系,可以判断一个字符串对象是否大于、等于或小于另一个字符串对象。具体返回结果如下: 当该字符串对象大于另一个字符串对象时,返回1; 当两个字符串对象相等时,返回0; 当该字符串对象小于另一个字符串对象时,返回-1。

eq:

String a = "Amit";
String b = "Sumit";
String c = new String("Amit");
System.out.println(a.equals(c));//true
System.out.println(a.compareTo(c)); //0
System.out.println(a.compareTo(b)); //1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接