Java 语言的几个缺陷之二: equals() 比较字符串

转载自:http://unmi.cc/java-language-defect-2-equals-compare-strings/

对于面向对象的语言不知道除了 Java 还有没别的语言会拿怎么比较两个字符串相等频频作为面试题来考. 原本是在编程语言中两个字符串内容是否相等时用 == 比较时却可能是不对的. 在 Java 中

"ab" == "ab"                                                                                   //true
"ab" == "new String("ab")                                                          //false
"ab" == String.value("ab")                                                         //true
new String("ab").equals(new String("ab"))                            //true
new String("ab").intern() == new String("ab").intern()      //true

在 Java 中明明看到两个字符串内容一样用 == 进行比较多数时候不是你想要的结果, 只有用 equals() 方法才是王道.  使用 Java 的字符串必须了解它内部是怎么存储的. 比于上面的结果我不作细说, 主要涉及到字符串常量池及内部状态, == 比较引用, equals() 比较内容.

Java 还常常对 equals 比较字符串津津乐道, 而我仍然认为它是语言设计上的一个缺陷, 所以 JVM 上的其他编程语言如 Groovy, Scala 纷纷倒勾, 无一不是用== 来比较字符串的内容, 它们也提供字符串引用的比较, 但多少人实际关心两个字符串的引用是否相同呢, 反正字符串设计的是 Immutable 的.

若说是因为 Java 不支持操作符的重载, 但可以像 Scala, Groovy 那样在编译器上下功夫的. 最终我想依然是受累于 100% 源代码与二进制的兼容性, 改进的话会造成早先代码的行为错乱.

Groovy 和  Scala  在比较两个字符串只管用 == 号, 它们能先判断引用是否相等, 然后再调用 equals() 方法来比较, 所以 == 比较内容时还不怕 null 值的干扰. Groovy 在调用 equalse() 之前会用 compareTo 先判断.

顺道一下, Groovy 想要比较引用时用 is() 方法, 如

1
2
3
4
groovy: 000 > "ab" .is( "ab" )
===> true
groovy: 000 > "ab" .is( new String( "ab" ))
===> false

而在 Scala 中要比较两引用时用 eq 或 ne 方法,如

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
scala> "ab" eq "ab"
res 13 : Boolean = true
 
scala> "ab" eq new String( "ab" )
<console> : 12 : warning : comparing a fresh object using `eq' will always yield false
  "ab" eq new String( "ab" )
  ^
res 14 : Boolean = false
 
scala> val v = new String( "ab" )
v : String = ab
 
scala> "ab" eq v
res 15 : Boolean = false
 
scala> "ab" ne v
res 16 : Boolean = true

Scala 也很聪明, 如果用 eq 时有一边是刚 new 出来的对象, 那么肯定是 false

C# 用 Object.referenceEquals() 来比较两个对象的引用, 看

1
2
3
4
char [] array = { 'a' , 'b' };
"ab" == new String(array);                          //true
Object.ReferenceEquals( "ab" , "ab" );                 //true
Object.ReferenceEquals( "ab" , new String(array));    //false

其他类似于脚本的语言只会更忠实的用== 比较内容.

要说能寻找到不能用 == 比较字符串的踪迹那就是 C/C++ 了, 传统 C 字符串必须用  strcmp 函数比较, C++ string 类型用 compare 函数. 其实 std:string 已对 == 操作符进行了重载, 所以也可以放心的用 == 比较两字符串的内容.

字符串是那么如此最常用的一种结构, Java 却使得它们在比较内容上让人如此迷惑, 造就了一道经典面试题. 容易出错而违反常规的东西不是什么好玩意, 一切当顺其自然才是.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值