这个程序的行为在1.4版和5.0版的Java平台上会有些变化。这个程序在这些版本上会分别做些什么呢?(如果你只能访问5.0版本的平台,那么你可以在编译的时候使用-source 1.4标记,以此来模拟1.4版的行为。) import java.util.Random. public class CoinSide { private static Random rnd = new Random(). public static CoinSide flip() { return rnd.nextBoolean() ? Heads.INSTANCE : Tails.INSTANCE. } public static void main(String[ ] args) { System.out.println(flip()). } }
class Heads extends CoinSide { private Heads() { } public static final Heads INSTANCE = new Heads(). public String toString() { return "heads". } }
class Tails extends CoinSide { private Tails() { } public static final Tails INSTANCE = new Tails(). public String toString() { return "tails". } }
该程序看起来根本没有使用5.0版的任何新特性,因此很难看出来为什么它们在行为上应该有差异。事实上,该程序在1.4或更早版本的平台上是不能编译的: CoinSide.java:7: incompatible types for ?: neither is a subtype of the other second operand: Heads third operand : Tails return rnd.nextBoolean() ? ^
在5.0或更新的版本中,Java语言显得更加宽大了,条件操作符在第二个和第三个操作数是引用类型时总是合法的。其结果类型是这两种类型的最小公共超类。公共超类总是存在的,因为Object是每一个对象类型的超类型。在实际使用中,这种变化的主要结果就是条件操作符做正确的事情的情况更多了,而给出编译期错误的情况更少了。对于我们当中的语言菜鸟来说,作用于引用类型的条件操作符的结果所具备的编译期类型与在第二个和第三个操作数上调用下面的方法的结果相同: T choose(T a,T b) { }
本谜题所展示的问题在1.4和更早的版本中发生得相当频繁,迫使你必须插入只是为了遮掩你的代码的真实目的而进行的转型。这就是说,该谜题本身是人为制造的。在5.0版本之前,使用类型安全的枚举模式来编写CoinSide对程序员来说会显得更自然一些[EJ Item 21]: 下面的程序全部是由同步化(synchronized)的静态方法组成的。那么它会打印出什么呢?在你每次运行这段程序的时候,它都能保证会打印出相同的内容吗? public class PingPong{ public static synchronized void main(String[] a){ Thread t = new Thread(){ public void run(){ pong(). } }. t.run(). System.out.print( "Ping" ). } static synchronized void pong(){ System.out.print( "Pong" ). } }