先看一段很简单的java代码:

toString()/**
* @author jeffwong
*/
public class InfiniteRecursion {
public String toString(){
return "InfiniteRecursion address "+ this + "\n";
} public static void main(String[] args) {
InfiniteRecursion obj = new InfiniteRecursion();
System.out.println(obj);
}
}

运行后,我们看到了一串异常信息,StackOverflow了:

爆栈的原因通常是因为递归或者无限循环,上面的代码造成堆栈溢出的直接原因是递归,下面来分析一下造成递归的原因:

定义类InfiniteRecursion,本来希望通过toString方法打印出当前对象的内存地址,获取当前对象当然会想到this关键字。在toString方法内,Java编译器发现一个字符串后面跟着一个加号,加号后面的对象不是String类型,所以编译器试着自动将this转换为字符串类型,也就是调用this.toString()方法,偏偏this所指代的这个对象重新实现了toString方法,于是造成循环不断地调用toString方法,这样就发生了递归调用。

上面这种toString()被Bruce Eckel总结称为无意识的递归,在.NET当中同样适用(重写ToString方法),类似代码我就不贴了。

这种无意识的递归说到底还是使用类继承不当造成的。也许你会说其实这根本没有什么技术难度的,类继承用对了不就行了吗,不就是继承自Object的区区一个ToString方法吗?

如果你手上维护的代码是一个基类代码丰富,继承链很深,含有大量包装类,类调用关系复杂……用对就行了,说起来未免太容易。再说一个由类继承引发的血案的真实案例:

用户反馈我司某重要业务部门的线上系统某页面无法正常打开,直观效果就是页面一直loading迟迟打不开。开发人员费了很大力气据说还动用了Windbg神器和传说中的架构师才排查到是一个页面方法调用的问题,为了说明问题我们暂时命名该页面为A,页面A继承自自定义基类页面B,然后出现问题的原因大致分析如下:

1、A页面某方法func1触发调用了基类B的另一个方法func2;

2、B中的方法func2执行的时候,发现被A重写了,所以就去执行A重写的方法func2;

3、A重写的func2内部又调用了func1,这样就重新触发A的func1的执行。

这样,一个神不知鬼不觉惊天地泣鬼神的无意识递归就形成了。

饱满而真实的类继承的副作用的经典案例介绍到此结束。

明天,你还会用类继承吗,你还敢用类继承吗,你还忍心用类继承吗?

参考:<<Thinking in Java>>

由Java中toString()方法引发的无意识的递归想到的的更多相关文章

  1. 自己(转)JAVA中toString方法的作用

    JAVA中toString方法的作用 因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.print ...

  2. JAVA中toString方法的作用

    因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不 ...

  3. JAVA中toString方法的作用(转)

    因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”. 它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不 ...

  4. JAVA中toString方法

    因为它是Object里面已经有了的方法,而所有类都是继承Object,所以"所有对象都有这个方法". 它通常只是为了方便输出,比如System.out.println(xx),括号 ...

  5. Java中的方法应用

    一.如何定义java中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 语法: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 public.protected.priv ...

  6. Java中的方法(形参及实参)return返回类型

    如何定义 Java 中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 一般情况下,定义一个方法的语法是: 其中: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 pub ...

  7. java中的方法method

    java中的方法必须存在于类class里,不能独立存在.类是描述具有某种特征的事物,方法则是这类 事物具有的某种功能,通过调用方法可以实现某种特定的功能.方法名一般以小写的动词开头. 例: publi ...

  8. Java09-java语法基础(八)java中的方法

    Java09-java语法基础(八)java中的方法 一.方法(函数/过程):是一个程序块,可以完成某种功能 1.java中方法的定义格式 [访问控制修饰符]  返回值类型  方法名(参数列表){ 方 ...

  9. Java学习笔记十一:Java中的方法

    Java中的方法 一:什么是方法: 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 学过C语言或者其他语言的应该都知道函数这个东西,在Java中,其实方法就是函数,只不过叫法不同,在 ...

随机推荐

  1. ORACLE rowid,file# 和 rfile#

    rowid简介 rowid就是唯一标志记录物理位置的一个id,在oracle 8版本以前,rowid由file#+block#+row#组成,占用6个bytes的空间,10 bit 的 file# , ...

  2. 自定义底部tab

    public class MainActivity extends TabActivity implements OnCheckedChangeListener { private RadioGrou ...

  3. Mahout源码分析之 -- 文档向量化TF-IDF

    fesh个人实践,欢迎经验交流!Blog地址:http://www.cnblogs.com/fesh/p/3775429.html Mahout之SparseVectorsFromSequenceFi ...

  4. 【POJ3237】Tree(树链剖分)

    题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...

  5. 编辑器sublime text3 破解码

    第一段亲测有效 —– BEGIN LICENSE —–Ryan ClarkSingle User LicenseEA7E-8124792158A7DE B690A7A3 8EC04710 006A5E ...

  6. R--相关分布函数、统计函数的使用

    分布函数家族: *func()r : 随机分布函数d : 概率密度函数p : 累积分布函数q : 分位数函数 func()表示具体的名称如下表: 例子 #r : 随机分布函数 #d : 概率密度函数 ...

  7. 使用 IntraWeb (41) - 数据控件速查

    TIWDBCheckBox 所在单元及继承链: IWDBStdCtrls.TIWDBCheckBox 主要成员: property AutoEditable: Boolean //根据 DataSou ...

  8. Odoo启动过程

    [本文基于odoo9源码编写] odoo包含的服务有 db object report workflow web[wsgi] Odoo以wsgi 规范提供Web及Web服务db/object/repo ...

  9. PyMongo下载及安装

    PyMongo最新版本下载地址: http://pypi.python.org/pypi/pymongo/#downloads PyMongo旧版本下载地址: http://pypi.python.o ...

  10. 云计算和大数据时代网络技术揭秘(八)数据中心存储FCoE

    数据中心存储演化——FCoE   数据中心三大基础:主机 网络 存储 在云计算推动下,存储基础架构在发生演变 传统存储结构DAS.SAN在发展中遇到了布线复杂.能耗增多的缺点(原生性),需要对架构做根 ...