Java 內存分析(程序實例),學會分析內存,走遍天下都不怕!!!

相信大多數的java初學者都會有這種經歷:碰到一段代碼的時候,不知該從何下手分析,不知道這段代碼到底是怎麼運行最後得到結果的… 等等吧,很多讓人頭疼的問題,作爲一名合格的程序員呢,遇到問題一定要思路清晰,不要將錯就錯,矇混過關,這一點很重要!
鑑於筆者最近惡補了java基礎,在這兒給大家總結了一些java代碼內存分析的經驗,希望可以對家有所幫助。
在分析內存之前呢,通過這個圖讓大家明白計算機是怎麼處理一個程序的。
在這裏插入圖片描述
簡單總結一下:1.計算機首先從硬盤拿到程序,加載(load)到內存區
2.操作系統找到main方法開始執行
3.執行代碼過程中的內存管理:
內存中分四塊:分別是heap(堆)、stack(棧)、data segment
(數據區)、code segmen(代碼區),各個區所存儲的內容圖中已
標註。

接下來,
給大家舉幾個例子程序,分別進行內存分析

**

程序一:

**

public class Person {

	static int id;
	static int age;
	
	Person(int _id, int _age) {
		id = _id;
		age = _age;
	}
	
	public static void main(String[] args) {
		Person tom = new Person(1,25);
		System.out.println("id= " + id + " age= " + age);

	}

}

內存分析圖:

第一步:從main方法入手,首先看到要實現一個Person類對象,該對象的名字是tom,則在stack中立馬分配出一塊空間用來存tom這個對象名,它指向heap中的Person對象(上文提到heap中存儲new出來的東西)

注:圖中局部變量tom的內容爲xxx,xxx實際爲Person對象在堆中的地址,在此處用xxx
代替。
在這裏插入圖片描述

第二步:調用Person中的構造方法,此時定義了兩個局部變量(要存儲到stack中)_id和_age,則立馬在stack中分配兩塊空間用於存儲這兩個局部變量,接下來把1和25分別傳給這兩個變量

在這裏插入圖片描述

第三步:執行id=_id; age=_age;這兩句,把_id和_age的值傳給Person對象

在這裏插入圖片描述

第四步:局部變量_id和_age消失(java的垃圾回收機制)

在這裏插入圖片描述

到此完成Person對象的創建,執行輸出語句,程序運行結束。

**

程序二:super引用,動態綁定及多態

**
說到多態,就先給大家鞏固一下動態綁定和多態的概念吧:
動態綁定:在執行期間(非編譯期間)判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。
簡單的來說,動態綁定就是根據實際new的對象所屬的類調用方法,幫助程序的擴展性達到極致。
多態的話,要知道多態產生的三個條件:
1.有繼承
2.有重寫
3.父類引用指向子類對象

//abstract 關鍵字 ---> 抽象類,抽象類一定被繼承,抽象方法一定被重寫
class Animal { //可以這樣聲明  absrtact class Animal
	private String name;
	Animal(String name) {  
		this.name = name;
	}
	
	public void enjoy() {  
		System.out.println("叫聲...");
	}
}

class Cat extends Animal{
	private String eyescolor;
	
	Cat(String n,String c) {
		super(n);
		eyescolor = c;
	}
	public void enjoy() {
		System.out.println("貓叫聲....");
	}
}

class Dog extends Animal {
	private String furCorlor;

	Dog(String n, String f) {
		super(n);
		furCorlor = f;
	}

	public void enjoy() {
		System.out.println("狗叫聲...");
	}
}

class Lady {
	private String name;
	private Animal pet;

	Lady(String name, Animal pet) {
		this.name = name;
		this.pet = pet;
	}

	public void petEnjoy() {
		pet.enjoy();
	}
}
public class TestAnimal {
	public static void main(String[] args) {
		Cat c = new Cat("catname","blue");
		Dog d = new Dog("dogname","black");
		c.enjoy();
		d.enjoy();

		Lady l1 = new Lady("l1",c);
		Lady l2 = new Lady("l2",d);
		l1.petEnjoy();
		l2.petEnjoy();
	}
}

內存分析圖:
老樣子,從main方法入手:

第一步,Cat c = new Cat(“catname”,“blue”);

當你new一個子類對象出來的時候,其內部就已經包含父類對象,並且該子類對象的super引用會指向其父類對象。
此處分兩小步給大家說明:(stack中局部變量的產生過程不再贅述,可參考程序一)
(1)new出來的Cat對象中包含Animal對象,Animal對象有一個成員變量name,自動初始化爲null,C對象有一個成員變量eyescolor,自動初始化爲null。
在這裏插入圖片描述
(2)傳“catname”和“blue”這兩個參數,“blue”直接賦值給eyescolor,而“catname”傳進去後,通過super(n)方法,調用其父類對象的構造方法,使name值等於“catname”
在這裏插入圖片描述

第二步,Dog d = new Dog(“dogname”,“black”);

內存分析同第一步(此處省略)

在這裏插入圖片描述

第三步,c.enjoy(); d.enjoy();

此時,c指向的是Cat對象,但是Cat對象中包含其父類Animal對象,這兩個對象都含有enjoy()方法,那麼應該調用哪一個呢?這就涉及到了java的動態綁定機制了,你new出來的對象實際是Cat對象,那麼就調用Cat對象的方法,而不是調用Animal對象的enjoy()方法;同理,d.enjoy()調用的是Dog對象的enjoy()方法。
所以,輸出結果爲在這裏插入圖片描述
第四步,Lady l1 = new Lady(“l1”,c);
Lady l2 = new Lady(“l2”,d);

內存分析圖:
在這裏插入圖片描述此處Animl的引用pet指向了其子類對象c,也就是上文提到的“父類引用指向子類對象”,並且,有繼承、有重寫,這就是多態。
每一個創建出來的對象都有this引用,指向他自身

第五步, l1.petEnjoy();
l2.petEnjoy();

調用Lady的petEnjoy()方法,輸出對應信息,最終輸出結果爲
在這裏插入圖片描述

程序三:數組

3.1 一維數組

public class Test {
	public static void main(String[] args) {
		Date[] days = new Date[3];
		for(int i=0;i<3;i++) {
			days[i] = new Date(2020,4,i+1);
		}
	}  
}
class Date {
	int year,month,day;
	Date(int y, int m, int d) {
		year = y;
		month = m;
		day = d;
	}
}

內存分析圖

在這裏插入圖片描述days指向堆中的一個數組,該數組中存放的是每一個Date對象的地址,每一個地址指向一個Date對象。(詳細賦值過程可參考程序一)

3.2 二維數組
二維數組實際上是一維數組的數組

public class Array {
	public static void main(String[] args) {
		int[][] a = new int[][] {
			{1,2,3},
			{4,5,6},
			{7,8,9}
		};
		
	}
}

內存分析圖
在這裏插入圖片描述棧空間中a指向一個一維數組,該數組每塊區域存放的是int型數組的地址。

筆者創作初期,如有不當之處,望批評指正。

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