Java中String的无意识的递归现象

  Java中的每个类从根本上都是继承Object,标准容器类自然也不。因此容器类都有toString()方法,并且覆写了这个方法,使得它生成的String结果能够表达容器自身,以及容器所包含的对象。例如ArrayList.toString(),它会遍历ArrayList中包含的所有对象,调用每个元素上的toString()方法:
Generator接口:

package com.jxs.chapeter13;

/**
 * Created by jiangxs on 2018/4/8.
 */
public interface Generator<T> {

    T next();
}

Coffee.java

package com.jxs.chapeter13;

/**
 * Created by jiangxs on 2018/4/8.
 */
public class Coffee {

    private static long counter = 0;
    private final long id = counter++;

    @Override
    public String toString() {

        return getClass().getSimpleName() + " " + id;
    }
}

    class Latte extends Coffee {
    }

    class Mocha extends Coffee {
    }

    class Cappuccino extends Coffee {
    }

    class Americano extends Coffee {
    }

    class Breve extends Coffee {
    }

CoffeeGenerator.java

package com.jxs.chapeter13;

import java.util.Iterator;
import java.util.Random;

/**
 * Created by jiangxs on 2018/4/8.
 */
public class CoffeeGenerator implements Generator<Coffee>,Iterable<Coffee> {

    private Class[] types = {Latte.class, Mocha.class,
            Cappuccino.class, Americano.class, Breve.class};
    private static Random random = new Random(47);

    public CoffeeGenerator() {
    }

    private int size;

    public CoffeeGenerator(int size) {
        this.size = size;
    }

    @Override
    public Coffee next() {

        try {
            return (Coffee) types[random.nextInt(types.length)].newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    class CoffeeIterator implements Iterator<Coffee> {

        int count = size;

        @Override
        public boolean hasNext() {

            return count > 0;
        }

        @Override
        public Coffee next() {
            count--;
            return CoffeeGenerator.this.next();
        }

        @Override
        public void remove() {

            throw new UnsupportedOperationException();
        }
    }

    @Override
    public Iterator<Coffee> iterator() {
        return new CoffeeIterator();
    }

    public static void main(String[] args) {

        CoffeeGenerator gen = new CoffeeGenerator();
        for (int i = 0; i < 5; i++) {
            System.out.println(gen.next());
        }
        for (Coffee c : new CoffeeGenerator(5)) {
            System.out.println(c);
        }
    }
}

ArrayListDisplay.java

package com.jxs.chapeter13;

import java.util.ArrayList;

/**
 * Created by jiangxs on 2018/4/8.
 */
public class ArrayListDisplay {

    public static void main(String[] args) {

        ArrayList<Coffee> coffees = new ArrayList<>();
        for (Coffee coffee : new CoffeeGenerator(10)) {
            coffees.add(coffee);
        }
        System.out.println(coffees);
    }
}

输出结果:

[Americano 0, Latte 1, Americano 2, Mocha 3, Mocha 4, Breve 5, Americano 6, Latte 7, Cappuccino 8, Cappuccino 9]

Process finished with exit code 0

  如果你需要toString()方法打印出对象的内存地址,也许你会考虑使用this这个关键字:
InfiniteRecursion.java

package com.jxs.chapeter13;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jiangxs on 2018/4/8.
 */
public class InfiniteRecursion {

    @Override
    public String toString() {
        return " InfiniteRecursion address: " + this + "\n";
    }

    public static void main(String[] args) {

        List<InfiniteRecursion> v = new ArrayList<>();
        for (int i=0;i<10;i++) {
            v.add(new InfiniteRecursion());
        }
        System.out.println(v);
    }
}

  当你创建了InfiniteRecursion对象,并将其打印出来的时候,你会得到一串非常长的异常。如果你将该InfiniteRecursion对象存入一个ArrayList中,然后打印该ArrayList,你也会得到同样的异常:

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:125)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    at java.lang.StringBuilder.append(StringBuilder.java:136)
    at com.jxs.chapeter13.InfiniteRecursion.toString(InfiniteRecursion.java:13)
    at java.lang.String.valueOf(String.java:2994)
···

其实,当代码运行时:

"InfiniteRecursion address: " + this

  这里发生了自动类型转换,由InfiniteRecursion类型转换成String类型。因为编译器看到一个String对象后面跟着一个”+”,而后面的对象不是String,于是编译器试着将this转换成一个String。它怎么转换呢,正是通过调用this上的toString()方法,于是就发生了递归调用。
  如果你真的想要打印出对象的内存地址,应该调用Object.toString()方法,这才是负责此任务的方法。所以,你不该使用this,而是应该调用super.toString()方法。
如下InfiniteRecursionModify.java所示:

package com.jxs.chapeter13;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jiangxs on 2018/4/8.
 */
public class InfiniteRecursionModify {

    @Override
    public String toString() {
        return " InfiniteRecursion address: " + super.toString() + "\n";
    }

    public static void main(String[] args) {

        List<InfiniteRecursionModify> v = new ArrayList<>();
        for (int i=0;i<10;i++) {
            v.add(new InfiniteRecursionModify());
        }
        System.out.println(v);
    }
}

输出结果:

[ InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@1540e19d
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@677327b6
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@14ae5a5
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@7f31245a
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@6d6f6e28
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@135fbaa4
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@45ee12a7
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@330bedb4
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@2503dbd3
,  InfiniteRecursion address: com.jxs.chapeter13.InfiniteRecursionModify@4b67cf4d
]

Process finished with exit code 0

参考:《Java编程思想》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值