java中堆栈区别,递归和迭代区别

来自:http://bbs.byr.cn/#!article/buptAUTA/31

1. 读取某个文件夹下的文件

  采用深度优先的方法,遍历文件夹,有文件就进行文件操作。

  深度优点方法:使用递归实现;

private void recursion (Path path) { 
   FileStatus[] children = fs.listStatus (path); 
   for(FileStatus child : children){ 
     if(child.isDir()){ 
       recursion(child.getPath()); 
     } 
     else{ 
       …… //执行文件处理代码 
     } 
   } 
} 

  注意:当路径深度很少的时候这样的方法不存在问题,但是如果路径大于100+,就会出现栈溢出的错误。

  Why?

  换成迭代实现

Stack<FileStatus> pathstack = new Stack<FileStatus>(); 
for(pathstack.push(fs.getFileStatus(path)); !pathstack.empty();){ 
   FileStatus cur = pathstack.pop(); 
   FileStatus[] children = fs.listStatus(cur.getPath()); 
   for(int i = 0; i < children.length; i++) { 
     final FileStatus child = children[i]; 
     if (child.isDir()) { 
       pathstack.push(child); 
     } 
     else { 
       …… //执行文件处理代码 
     } 
   } 
} 

  问题消失了~~Why?

2. 堆和栈的区别

  堆是有序完全二叉树,栈是一种先进后出的线性表,栈的特点是速度快,jvm的压栈和出栈操作都是非常高效的(相对来说,堆的二叉树遍历是要比先进后出线性表要慢的)。

  每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆,对象的大小是不可估计的,是动态的。

  对象的应用却放在栈中,一个对象对应了一个4btye的引用。

  

3. 递归和迭代的区别

  递归是通过一个函数进行的,函数使用了栈空间存放在函数中申明的基本数据类型(例如int,char)和堆中对象的引用(注意是引用,而非对象本身)。所以递归由于不断调用自身函数体,因此会导致需要使用的栈空间不断增加,最终导致栈溢出。

  迭代是在一个函数中的循环体,迭代使用的pathstack这个变量,在JVM栈中只有一个4字节的指针(引用的本质),而变量的主体本身使用的则是堆内存空间。

  堆空间相对于栈空间来说要大得多,但是如果无限制的使用堆空间,当然也会溢出,这就是java程序员都经常会遇到的OOM(OutOfMemoryError)异常。OOM异常是非常常见的堆溢出,而StackOverFlow这个栈溢出异常则非常少见,如文章所言,栈中只存放一些4字节的指针,所以虽然栈空间很小,但想撑爆栈空间也不是那么容易的事情,这就是为什么本地应用很难遇到栈溢出的原因。

  递归就是在过程或函数里面调用自身,而迭代是利用变量的原值推算出变量的一个新值。如果递归是自己调用自己的话,迭代就是A不停的调用B。显然递归用了栈空间,迭代因为始终在一个函数体中,所以使用的是堆空间。迭代只会导致堆溢出(OOM)而不会导致栈溢出。 
  迭代不会使用栈空间,所以当然不会导致栈溢出。Stack类的实例变量因为使用的内存空间是处于堆空间中,因此当然可以避免栈溢出。
 

原文地址:https://www.cnblogs.com/lxq0309/p/3663271.html