27 February 2014

用多了像Java这样的高层次语言容易让人变得懒惰和想当然。在C语言里,==非常纯粹,没人会用它来判断两个字符串是否相同。 但在Java里却会经常不经意地出现诸如if (str == "") {...}这样的代码。

这样的代码有时候是对的。但不对的时候,这错误又很难发现。今天遇到的一个bug就是用==来判断字符串相等导致的。

Java里的字符串类是String。String类型的变量都是引用型变量。直接用==来比较两个引用变量的话,实际比较的是它们所引用的对象的地址, 只有二者指向同一个对象时才会相等,并不能判断两个对象的内容是否相同。从这个角度说,试图用==比较两个字符串的内容其出发点就是错误的。

但为什么容易犯这样的错误呢?主要是存在一些误导。第一,有些语言确实是用==来判断两个字符串内容是否一样的。第二,在有的高级语言里,允许类进行操作符重载(C++,说的就是你!),将==重新实现为比较两个对象的内容。第三,Java语言本身支持用++=操作符对字符串进行连接,这也容易让人觉得字符串可以像数值那样比较相等。

还有最坑爹的一个误导就是,有时候用==比较Java字符串竟然会得到正确的结果!

Java程序在运行的时候会维护一个字符串池。这个池子里包括程序中所有的字符串常量。如果两个String变量内容是相同的常量,那么它们指向的都是字符串池中的那个常量的地址。 结果用==比较它们时确实会相等。String类还有一个intern方法,可以将任意字符串加入池中。上述机制的主要出发点在于节省内存,但由此也导致了一些混乱,使得有些程序员侥幸逃过了用==比较字符串的惩罚。

但我们不能存侥幸心理。以后比较字符串内容时完全不要用==,而应该用字符串类的equals方法。更多细节可参见http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java

在Objective-C里,也有类似的问题。我记得我在写iOS应用的时候也出现过用==比较字符串内容的代码,不过好在及时纠正了。