George Orwell的《畜牧场(Animal Farm)》一书的读者可能还记得老上校的宣言:“所有的动物都是平等的。”下面的Java程序试图要测试这项宣言。那么,它将打印出什么呢? public class AnimalFarm{ public static void main(String[] args){ final String pig = "length: 10". final String dog = "length: " pig.length(). System.out. println("Animals are equal: " pig == dog). } }
对该程序的表面分析可能会认为它应该打印出Animal are equal: true。毕竟,pig和dog都是final的string类型变量,它们都被初始化为字符序列“length: 10”。换句话说,被pig和dog引用的字符串是且永远是彼此相等的。然而,==操作符测试的是这两个对象引用是否正好引用到了相同的对象上。在本例中,它们并非引用到了相同的对象上。 你可能知道String类型的编译期常量是内存限定的。换句话说,任何两个String类型的常量表达式,如果标明的是相同的字符序列,那么它们就用相同的对象引用来表示。如果用常量表达式来初始化pig和dog,那么它们确实会指向相同的对象,但是dog并不是用常量表达式初始化的。既然语言已经对在常量表达式中允许出现的操作作出了限制,而方法调用又不在其中,那么,这个程序就应该打印Animal are equal: false,对吗? 嗯,实际上不对。如果你运行该程序,你就会发现它打印的只是false,并没有其它的任何东西。它没有打印Animal are equal: 。它怎么会不打印这个字符串字面常量呢?毕竟打印它才是正确的呀!谜题11的解谜方案包含了一条暗示: 操作符,不论是用作加法还是字符串连接操作,它都比 == 操作符的优先级高。因此,println方法的参数是按照下面的方式计算的: System.out.println(("Animals are equal: " pig) == dog).
这个布尔表达式的值当然是false,它正是该程序的所打印的输出。 有一个肯定能够避免此类窘境的方法:在使用字符串连接操作符时,总是将非平凡的操作数用括号括起来。更一般地讲,当你不能确定你是否需要括号时,应该选择稳妥地做法,将它们括起来。如果你在println语句中像下面这样把比较部分括起来,它将产生所期望的输出Animals are equal: false : System.out.println("Animals are equal: " (pig == dog)).