Java基础整理--方法、方法执行内存分析、重载与递归

方法

  1. 方法产生的机制
  • 某个功能代码只需要写一遍
  • 要使用这个功能只需要给这个功能传递具体的数据
  • 这个功能完成之后返回一个最终的结果
    这样代码就可以重复利用,提高代码复用性
  1. 在返回值类型是void的方法中使用 return 语句用于终止方法的执行
public static void fun(){
        for(int i = 0; i < 6; i++){
            if(i == 3)
                return ; //此处的 return相当于 break
            System.out.println("Hello");
        }
    }

方法执行内存分析

方法在执行过程当中,在JVM中的内存是如何分配的呢,内存是如何变化的?

  1. 方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配“运行所属”的内存空间。只有在调用这个方法的时候,才会动态地给这个方法分配所属的内存空间。
  2. 在JVM内存划分上有这样三块主要的内存空间(当然除了这三块之外还有其他的内存空间):
    方法区内存、堆内存、栈内存
  3. 数据结构栈的特点?
    在这里插入图片描述
  1. 栈帧永远指向栈顶元素
  2. 栈顶元素处于活跃状态,其他元素静止
  3. 术语: 压栈/入栈/push ; 弹栈/出栈/pop
  4. 栈数据结构存储数据的特点:先进后出,后进先出
  1. 方法代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
  • 方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候将其放到了方法区内存当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据。存放了代码片段。
  • 代码片段虽然在方法区内存当中只有一份,但是可以被重复利用。每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。【栈内存中分配方法运行所属的内存空间】
  1. 方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。
  • 压栈:给方法分配内存
  • 弹栈:释放该方法的内存空间
  1. 局部变量在方法体中声明,局部变量运行阶段内存在栈中分配。

【案例1】
分析以下程序运行时的内存空间分配

public class MyTest {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int retValue = sumInt(a, b); //等于号先执行完右边,然后分配retValue的内存空间
        System.out.println("retValue = " + retValue);
    }

    public static int sumInt(int i, int j) {
        int result = i + j;
        int num = 3;
        int retValue = divide(result, num);
        return retValue;
    }

    public static int divide(int x, int y) {
        int z = x / y;
        return z;
    }
}

在这里插入图片描述
分析:

  1. 按照程序自上而下执行的顺序,查看哪些字节码文件会被加载到方法区内存,分别是本类编译后的字节码文件,String.class以及System.class,三者依次加载到方法区内存中
  2. 在执行方法的时候给方法分配栈内存空间,为局部变量分配内存空间。如main方法中的a和b变量,然后为sumInt方法分配栈内存空间,依次为i, j, result, num分配内存空间,然后分配divide的内存空间;继续依次分配x, y和z的内存空间,return z;语句执行结束后分配sumInt方法中的retValue内存,执行完return retValue;语句后分配main方法中的retValue空间。

【案例2】
分析以下程序的内存空间分配

public class MyTest {
    public static void main(String[] args) {
        int i = 10;
        method(i);
        System.out.println("main -->" + i); // i=10
    }

    public static void method(int i) {
        i++;
        System.out.println("method -->" + i);// i=11
    }
}

在这里插入图片描述

方法重载

  1. 方法重载又被称为:overload
  2. 什么时候考虑使用方法重载?
  • 功能相似的时候,尽可能让方法名相同。但是:功能不同/不相似的时候,尽可能让方法名不同。
  1. 什么条件满足之后构成了方法重载?
  • 在同一个类中
  • 方法名相同
  • 参数列表不同:数量不同,顺序不同,类型不同
  1. 方法重载和什么有关系,和什么没有关系?
  • 方法重载和方法名+参数列表有关系
  • 方法重载和返回值类型无关
  • 方法重载和修饰列表无关

方法递归

  1. 什么是递归?
    递归就是方法自身调用自身
  2. 递归是很耗费栈内存的,递归算法可以不用时尽量别用
  3. 栈内存溢出的结果是JVM停止工作
    栈内存发生溢出错误,错误时无法挽回的,只有一个结果,就是JVM停止工作
    以下程序会发生栈内存溢出错误(java.lang.StackOverflowError)【不是异常,是错误】
    public static void main(String[] args) {
        dosome();
    }

    public static void dosome() {
        System.out.println("dosome begin");
        dosome();
        System.out.println("dosome end");
    }
  1. 递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误
  2. 递归即使有了结束条件,即使结束条件是正确的,也有可能发生栈内存溢出错误,因为递归的太深了
    【案例】
    用递归实现求1+2+…+n
   public static void main(String[] args) {
        int n = 4;
        System.out.println(doSum(n));
    }

    public static int doSum(int n){
        if(n==1)
            return 1;
        else
            return n+doSum(n-1);
    }
	//思路:
	//n+sum(n-1)
	//4+sum(3)
	//4+3+sum(2)
	//4+3+2+sum(1)
	//4+3+2+1

上述程序的内存空间分配情况:
在这里插入图片描述
用一个更形象的图来表示递归调用过程,就是如下图所示,将该图逆时针旋转90度就是一个栈。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/shao_yc/article/details/106559108