🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## [意外递归](https://lingcoder.gitee.io/onjava8/#/book/18-Strings?id=%e6%84%8f%e5%a4%96%e9%80%92%e5%bd%92) Java 中的每个类从根本上都是继承自`Object`,标准集合类也是如此,它们都有`toString()`方法,并且覆盖了该方法,使得它生成的`String`结果能够表达集合自身,以及集合包含的对象。例如`ArrayList.toString()`,它会遍历`ArrayList`中包含的所有对象,调用每个元素上的`toString()`方法: ~~~ // strings/ArrayListDisplay.java import java.util.*; import java.util.stream.*; import generics.coffee.*; public class ArrayListDisplay { public static void main(String[] args) { List<Coffee> coffees = Stream.generate(new CoffeeSupplier()) .limit(10) .collect(Collectors.toList()); System.out.println(coffees); } } /* Output: [Americano 0, Latte 1, Americano 2, Mocha 3, Mocha 4, Breve 5, Americano 6, Latte 7, Cappuccino 8, Cappuccino 9] */ ~~~ 如果你希望`toString()`打印出类的内存地址,也许你会考虑使用`this`关键字: ~~~ // strings/InfiniteRecursion.java // Accidental recursion // {ThrowsException} // {VisuallyInspectOutput} Throws very long exception import java.util.*; import java.util.stream.*; public class InfiniteRecursion { @Override public String toString() { return " InfiniteRecursion address: " + this + "\n" } public static void main(String[] args) { Stream.generate(InfiniteRecursion::new) .limit(10) .forEach(System.out::println); } } ~~~ 当你创建了`InfiniteRecursion`对象,并将其打印出来的时候,你会得到一串很长的异常信息。如果你将该`InfiniteRecursion`对象存入一个`ArrayList`中,然后打印该`ArrayList`,同样也会抛出异常。其实,当运行到如下代码时: ~~~ "InfiniteRecursion address: " + this ~~~ 这里发生了自动类型转换,由`InfiniteRecursion`类型转换为`String`类型。因为编译器发现一个`String`对象后面跟着一个 “+”,而 “+” 后面的对象不是`String`,于是编译器试着将`this`转换成一个`String`。它怎么转换呢?正是通过调用`this`上的`toString()`方法,于是就发生了递归调用。 如果你真的想要打印对象的内存地址,应该调用`Object.toString()`方法,这才是负责此任务的方法。所以,不要使用`this`,而是应该调用`super.toString()`方法。