2 myselfyonghu myselfyonghu 于 2015.05.31 17:14 提问

关于String中的一个递归问题

今天学习java String时,遇到书上讲的一个递归问题,先上代码
import java.util.*;
public class InfiniteRecursion {

public String toStirng() {
    return "InfiniteRecursion address: "+ this +"\n";
}
public static void main(String[] args) {
    List<InfiniteRecursion> list = new ArrayList<InfiniteRecursion>();
    for(int i = 0; i <2; i++)
        list.add(new InfiniteRecursion());
    System.out.println(list);
}

}
书上讲到在toString()方法里面,编译器会将this转化为String,而转换时会调用toString()方法,这样就产生了递归调用。。我思考了也这么觉得,,但是运行代码时没有报错。把this换成super.toString()也能运行。求请教,为什么没有递归(书上讲的java SE5,我的编译器是1.7的)。

7个回答

caozhy
caozhy   Ds   Rxr 2015.05.31 17:20

不会递归。因为你重写的是InfiniteRecursion的toString,而你调用的是List<InfiniteRecursion>的toString

tongyi55555
tongyi55555 回复薛浩: 确实如此,list中调用的也是InfiniteRecursion中的toString方法。
2 年多之前 回复
myselfyonghu
myselfyonghu 调用List<InfiniteRecursion>的toString()时它会遍历List中包含的InfiniteRecursion,那么也会调用InfiniteRecursion的toStirng()方法呀。
2 年多之前 回复
lzp_lrp
lzp_lrp   Ds   Rxr 2015.05.31 17:27

这么写才会递归调用

package string;

public class InfiniteRecursion {

@Override
public String toString() {
    //this关键字会调用this.toString()方法,产生递归
    //修改为super.toString()
    return "InfiniteRecursion : " + this;  
}

public static void main(String[] args) {
    InfiniteRecursion ir = new InfiniteRecursion();
    System.out.println(ir.toString());  //Exception in thread "main" java.lang.StackOverflowError

}

}

caozhy
caozhy   Ds   Rxr 2015.05.31 17:29

不会调用toString

http://ideone.com/cffA6l
返回的是类名@引用地址

caozhy
caozhy   Ds   Rxr 2015.05.31 17:30
import java.util.*;
class Ideone {
public String toStirng() {
    return "InfiniteRecursion address: "+ this +"\n";
}
public static void main(String[] args) {
    List<Ideone> list = new ArrayList<Ideone>();
    for(int i = 0; i <2; i++)
        list.add(new Ideone());
    System.out.println(list);
}
}

在线编译运行结果
[Ideone@b8fba5, Ideone@9133f6]

tongyi55555
tongyi55555   2015.05.31 18:12

我的测试代码:

     public static void main(String[] args) {
        EverhThingTest ett = new EverhThingTest();
        ett.printList();
        // ett.printAbclr();
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "ssss"+this+"\n";
    }
    private void printList() {
        // TODO Auto-generated method stub
        List<EverhThingTest> list = new ArrayList<EverhThingTest>();
        list.add(new EverhThingTest());
        list.add(new EverhThingTest());
        System.out.println(list);
    }

你这个问题确实很有意思,建议你在输出时打个断点跟一下,我根据你的代码测试了一下,我这里是可以递归调用,程序没有结果,会报Exception in thread "main" java.lang.StackOverflowError。从下面的错误信息可以看到递归调用了,如下:

     Exception in thread "main" java.lang.StackOverflowError
    at java.lang.System.arraycopy(Native Method)
    at java.lang.String.getChars(String.java:854)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391)
    at java.lang.StringBuilder.append(StringBuilder.java:119)
    at java.lang.StringBuilder.<init>(StringBuilder.java:93)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at EverhThingTest.toString(EverhThingTest.java:16)
    at java.lang.String.valueOf(String.java:2826)
    后面还有...

我在JDK1.6和1.7上都试过了,都是不可以的。不知道你的1.7为啥不能递归调用。

顺便说一下,输出list时,调用的toString方法在AbstractCollection类中(我两次跟代码都是跟到了这里,你自己看下是不是一致),代码如下:

     public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

上面的sb.append(e == this ? "(this Collection)" : e);语句中,会调用StingBuilder的append(Object obj)方法,代码如下:

     public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

而上面的String.valueOf(obj)方法的代码如下:

     public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

可以看到,最终还是指向了obj的toString方法,也就是你自己定义的toString方法。

建议你断点调试下,看看问题所在,期待你的回复。

myselfyonghu
myselfyonghu 你回复的很详细,但是我对java的理解还不是很深,正在学习阶段,我会好好阅读你的回复。我刚贴的问题中,在main方法中使用List保存外部类对象,这样就会产生递归,而在List中保存main所属类对象时没有递归。
2 年多之前 回复
myselfyonghu
myselfyonghu   2015.05.31 18:15

刚才那个确实没有调用InfiniteRecursion的toString()方法,但是现在这个是调用了RecursionTest的toString()方法。而且也发生了递归。
import java.util.ArrayList;
import java.util.List;
class RecursionTest {
public String toString() {
System.out.println("this is called");
return "recursion: "+this;
}
}
public class Test {

public static void main(String[] args) {

    List<RecursionTest> lr = new ArrayList<RecursionTest>();
    lr.add(new RecursionTest());
    System.out.println(lr);
}

}

myselfyonghu
myselfyonghu 回复那一抹代码: 能产生递归,我把toString()方法名写错了。。谢谢您的指教。
2 年多之前 回复
myselfyonghu
myselfyonghu 回复那一抹代码: 还是不会递归,我试了你的代码,产生了递归。你把我第一次发的代码拷到你的环境下试试什么结果。
2 年多之前 回复
tongyi55555
tongyi55555 对这个不是很感兴趣,您那个不调用递归的能否再试一下,看看是否还是不能调用?很想知道为何调用不了,断点调试试试。
2 年多之前 回复
myselfyonghu
myselfyonghu   2015.05.31 19:27

统一回复一下,我把toString()方法名写错了,并没有调用我的这个方法,所以最终还是会调用toString()的,也产生了递归了。

tongyi55555
tongyi55555 呵呵,这个回复够狠。
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片