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度就是一個棧。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章