假设这个错误终于被改正了,但同时,类 Example 的一个子类也被创建了,如清单 2 所示:

清单 2. 试图捕捉象清单 1 这样的不正确的调用

 

  import java.util.*; 

  class Example { 

  public int product(Iterator i) { 

  return productHelp(i, 1); 

  } 

  int productHelp(Iterator i, int accumulator) { 

  if (i.hasNext()) { 

  return productHelp(i, accumulator * ((Integer)i.next()).intValue()); 

  } 

  else { 

  return accumulator; 

  } 

  } 

  } 

  // And, in a separate file: 

  import java.util.*; 

  public class Example2 extends Example { 

  int productHelp(Iterator i, int accumulator) { 

  if (accumulator <1) { 

  throw new RuntimeException("accumulator to productHelp must be >= 1"); 

  } 

  else { 

  return super.productHelp(i, accumulator); 

  } 

  } 

  public static void main(Stringargs) { 

  LinkedList l = new LinkedList(); 

  l.add(new Integer(0)); 

  new Example2().product(l.listIterator()); 

  } 

  }


类 Example2 中的被覆盖的 productHelp 方法试图通过当 accumulator 小于“1”时抛出运行时异常来捕捉对 productHelp 的不正确调用。不幸的是,这样做将引入一个新的错误。如果 Iterator 含有任何 0 值的实例,都将使 productHelp 在自身的递归调用上崩溃。

现在请注意,在类 Example2 的 main 方法中,创建了 Example2 的一个实例并调用了它的 product 方法。由于传给这个方法的 Iterator 包含一个 0,因此程序将崩溃。

然而,您可以看到类 Example 的 productHelp 是严格尾递归的。假设一个静态编译器想把这个方法的正文转换成一个循环,如清单 3 所示:

清单 3. 静态编译不会优化尾调用的一个示例

 

  int productHelp(Iterator i, int accumulator) { 

  while (i.hasNext()) { 

  accumulator *= ((Integer)i.next()).intValue(); 

  } 

  return accumulator; 

  }


于是,最初对 productHelp 的调用,结果成了对超类的方法的调用。超方法将通过简单地在 iterator 上循环来计算其结果。不会抛出任何异常。

用两个不同的静态编译器来编译这段代码,结果是一个会抛出异常,而另一个则不会,想想这是多么让人感到困惑。