Java基礎6--面向對象--程序運行內存圖解

6-1,二維數組的定義方式

1,定義:int[][] arr = new int[3][2];

創建一個二維數組,這個其實是有三個一維數組,一維數組中的每個元素又引用了一個一維數組。

2,打印而爲數組:

Sop(arr);直接打印二維數組。 打印[[I@C17164,[[是二維數組的意思,I是int的意思。

Sop(arr[0]);直接打印二維數組中角標爲0的一維數組。打印[I@b8e622,[是一維數組的意思。

Sop(arr[0][0]);直接打印二維數組中腳標爲0的一位數組的角標爲0的元素。打印0。

3,int[][] arr = new int[3][2];

    arr[1][1]= 88;

的內存圖解:


步驟:

(1)從main函數進入,讀到arr局部變量,把arr入棧。

(2)因爲arr是數組類型的,所以在堆內存中創建實體,創建一個一維數組,附地址0X0045,並將三個元素初始化爲null,因爲每個元算又引用到一個一位數組。

(3)堆中的每個元素又是一個一維數組,在堆中新創建三個一維數組,並分配地址值,初始化爲0,因爲是int型。再把int型數組的地址值賦給之前創建的相應的一位數組的元素。

(4)將數組的引用地址賦值給棧空間的arr,arr指向了0X0045內存地址。

(5)第一句話讀完,讀下面的一句,給角標爲[1][1]的元素賦值爲88,這時根據arr的引用地址可以找到0X0045的數組位置,根據第一個[1]可以找到這個數組角標1指向的地址,找到0X0034指向的數組,再根據第二個[1]找到角標爲1的元素,這時這個元素是0,然後直接賦值爲88,執行完畢。

 

6-2,創建子數組長度不等的二維數組

方式:

int[][] arr = new int[3][];
//分別對二維數組中的每一個小數組進行初始化
arr[0] = new int[2];
arr[1] = new int[1];
arr[2] = new int[3];

步驟:

(1)從main開始程序,讀到int數組型局部變量arr,將arr進棧操作。

(2)arr是一個數組,在堆內存中創建一個一位數組,分配內存地址。

(3)arr有三個元素,創建一個大小爲3的一維數組,其中每一個元素又指向了另一個一維數組,所以賦給初始值null。但是因爲創建二維數組時是以new int[3][]這種方式創建的,也就是第二個沒值,所以這時不能創建那三個一維數組,此時內存中只有最上面的長度爲三的一位數組。

(4)將數組的地址賦給棧內存中的arr,arr引用指向堆內存中的數組的地址。

(5)讀到第二句,創建了一個一維數組,這時纔在內存中創建地址爲0X0034的數組,大小爲2,初始化元素值爲0,並將這個地址賦給原來數組中的[0]號元素。

(6)讀到第三句,創建一個長度爲1的一維數組,地址爲0X0021,賦給arr[1]。

(7)讀到第四句,創建一個長度爲3的一維數組,地址爲0X0078,賦給arr[2]。 結束。

 

另外:

int[][] arr = new int[3][];

Sop(arr); //[[I@c17164

Sop(arr[0]); //null

Sop(arr[0][0]); //錯誤,拋出異常NullPointerException空指針異常

因爲這種定義方式當前沒有定義arr[0][0]元素,只在堆中創建了一個長度爲3的一維數組,三個小數組並沒有開闢內存空間,也沒有地址值,所以無法訪問。

 

6-3,二維數組的另一種定義方式

在明確二維數組中的元素時可以這麼定義:

int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};

遍歷上述數組:

for(int x=0;x<arr.length;x++) {
	for(int y=0;y<arr[x].length;y++) {
		System.out.println(arr[x][y]+",");
	}
}

2,打印長度:

Sop(arr.length);//打印二維數組的長度,其實就是打印一維數組的個數。

Sop(arr[0].length);//打印二維數組中角標爲0的數組的長度。

 

6-4,面向對象

1,面向過程強調的是過程,如C語言。

面向對象強調的是對象,如C++、Java、C#。

2,面向對象的特點:

(1)面向對象是一種常見的思想,符合人們的思考習慣。

(2)面向對象的出現,將複雜的問題簡單化。

(3)面向對象的出現,讓曾經在過程中的執行者,編程了對象中的指揮者。

3,如何理解面向對象?

在面試中可以這麼說,這也有助於理解。

首先先說出上面的三個特點。然後再說下面。

其實面試官您就是按照面向對象的方式做事情,憑您的能力,您完全可以設計並開發項目的任務,達成目標,但這樣是您一個人做,既費時又費力,這時您就需要找一些具備編程知識的人來幫您完成目標,您來指揮我們做事情,因爲我們具備專業開發這種功能,所以能夠幫您完成項目,達成目標,而我就是滿足這一條件的人,您只需要通知我做什麼事情即可,我會給您一個滿意的答覆,但至於我是如何完成這件事情的,您就不用關心了。

4,如果Java中已經有了這個對象,就直接用,如果沒有,就創建對象。

5,面向對象的三個特徵:封裝、繼承、多態。

 

6-5,類與對象之間的關係

用Java語言對現實生活中的事務進行描述,通過類的形式來表現,怎麼描述呢?

對於事物描述通常只關注兩個方面,一個是屬性,一個是行爲。

只要明確事物的屬性和行爲並定義在類中即可。

對象:其實就是該類事物實實在在存在的客體。

 

類與對象之間的關係:

類:事物的描述。

對象:該類事物的實例。在Java中是通過new創建的。

 

6-6,類與對象的體現

描述一個Car並運行。

//描述Car,通過類的形式
class Car{
	//定義車輪的數量,是Car的屬性
	int num;
	//定義車子的顏色,是Car的屬性
	String color;
	//車子可以跑起來,是Car的行爲
	void run() {
		System.out.println(num+"::"+color);
	}
}
class CarDemo{
	public static void main(String[] args) {
		//在計算機中創建一個Car的實例,通過new關鍵字
		//c就是一個類類型的引用變量,指向了該類的對象。
		Car c = new Car();
		//爲這個Car實例添加屬性,使它成爲一個有四個輪子的紅色車
		c.num = 4;
		c.color = "red";
		//讓這個Car在公路上行駛
		c.run();
	}
}

細節:

(1)定義類其實就是定義類中的成員。

成員:成員變量==屬性,成員函數==行爲。

(2)Car類中不需要定義主函數,因爲Car不需要獨立運行,只有被用到的時候才運行。

 

6-7,對象的內存體現:

1,首先明確,通過new建立的都在堆內存當中。

2,上例中Car類的內存圖示如下:

Car c = new Car();

c.num = 4;

c.color = "red";

c.run();

步驟:

(1)從入口main開始執行程序,把局部變量c加載到棧內存。

(2)new Car();在堆內存中開闢了一片空間,並分配地址,將Car的非static的屬性也加在到這片堆內存空間中,並默認初始化屬性值,int型初始化爲0,String初始化爲null。

(3)c = new Car();將地址0X0078賦給變量c,c指向堆中的空間。

(4)c.num = 4,c.color = “red”;用c指向堆中的地址,找到這個變量,並賦值。

(5)最後一局c.run();運行run函數。

 

6-8,成員變量和局部變量的區別

1,區別:

(1)成員變量定義在類中,整個類都可以訪問。

    局部變量定義在函數裏、語句、局部代碼塊中,只在所屬區域有效。

(2)成員變量存在於堆內存的對象中。

    局部變量存在於棧內存的方法中。

(3)成員變量隨着對象的創建而存在,隨着對象的消失而消失。

    局部變量隨着所屬區的執行而存在,隨着所屬區域的結束而釋放。

(4)成員變量都有默認的初始值。

    局部變量沒有默認的初始值。

2,上面的例子中,c.num = 4;不是給classCar中的num賦值,而是給對象中c中的num賦值。

 

6-9,成員變量和局部變量的同名&顯示初始化

class Car{
	int num = 4;	//在堆內存中顯示初始化
	String color;
	void run() {
		int num = 10;
		System.out.println(num + "::" + color);
	}
}

在run方法中有一個與成員變量同名的num。Car的run方法運行的時候,要加載到棧內存裏,而且run中的num也加在到棧裏的run方法中,run執行的時候,發現棧裏有這個變量,就不再去堆內存找了,所以運行出來是10。

 

6-10,類類型參數

class Demo{
	public static void main(String[] args) {
		Car c1 = new Car();
		Car c2 = new Car();
		show(c1);
		show(c2);
	}
	//類類型的變量一定指向對象,要麼就是null
	public static void show(Car c) {
		c.num = 3;
		c.color = "black";
		System.out.println(num+"::"+color);
	}
}

6-11,匿名對象

1,匿名對象:沒有名字的對象。

2,用法:

(1)當對象方法僅進行一次調用的時候,就可以簡化成匿名對象。

(2)匿名對象可以作爲實際參數進行傳遞。

例如:

Car car = new Car();

car.run();

上面的兩句可以使用new Car().run();代替。

 

Car car = new Car();

car.run();

car.run();

上面的三句就不可以使用:

new Car().run();

new Car().run();

代替,因爲如果這麼寫,是兩個不同的對象,每new一次就在內存中創建一個對象。

 

3,

new Car().num = 5;

new Car().color = "green";

new Car().run();

的內存圖示:

由於沒有局部變量,所以沒有棧內存。


步驟:

(1)第一句new Car().num = 5;執行,創建了圖中的第一個對象,賦值5以後,在棧中並沒有任何的變量接收這個地址值,所以第一句結束時候,這個對象就變成垃圾了。

(2)第二個與第一個相同。

(3)所以,如果打印num和color,是0和null。

 

 

6-12,基本數據類型參數傳遞圖解

class Demo{
	public static void main(String[] args) {
		int x = 3;
		show(x);
		System.out.println("x=" + x);
	}
	public static void show(int x) {
		x = 4;
	}
}

本例沒有實體,不涉及到堆內存。



步驟:

(1)從main函數開始,main函數進棧,局部變量x=3進棧。

(2)調用show方法,show方法進棧。

(3)將main中的x作爲參數傳遞給show函數,這時show函數裏也有一個x變量,且等於3。

(4)執行show中的x=4操作,show中的x變爲4,main中的x不變,如圖。

(5)show方法執行結束,show彈棧。回到main中,main中的x依然是3,所以最後打印x=3。

 

6-13,引用數據類型參數傳遞圖解

class Demo{
	int x = 3;
	public static void main(String[] args) {
		Demo d = new Demo();
		d.x = 9;
		show(d);
		System.out.println(d.x);
	}
	public static void show(Demo d) {
		d.x = 4;
	}
}

圖解:


(1)從main函數開始,main進棧,有一個局部變量d,d也進棧,並在main中。

(2)new Demo();開闢了對內存空間,分配地址,並把成員變量默認初始化爲0,類中定義x=3,就顯示賦值爲3,創建完畢,將地址0X0045賦值給d。

(3)讀到d.x = 9;根據d的引用找到堆中的對象的x,並賦值爲9。

(4)調用show方法,show中有一個局部變量Demo類型的d,這個局部變量也進入到棧的show方法中。

(5)將main中的d的引用地址值賦值給show中的d,此時可見,show中的d也指向了堆中的同一個對象,因爲地址是相同的。

(6)在show方法中,調用d.x = 4;根據這個d的地址找到同一個對象,將對象中的x改爲4。

(7)show方法運行結束,彈棧。

(8)接着執行main剩下的語句,打印d引用對象的x變量的值,此時,d依然指向那個對象,這個對象中的x最後被改爲4,所以打印爲4。

 

 

6-14,面向對象-封裝

1,封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。

封裝的好處:

(1)將變化隔離,安全性高,裏面如何變化,外面使用不受影響。

(2)方便使用。

(3)提高重要性。

(4)提高安全性。

封裝原則:

將不需要向外提供的內容都隱藏起來。

把屬性都隱藏,提供公共方法對其訪問。

 

2,封裝思想:

Private :私有:是一個權限修飾符,用於修飾成員,不能修飾局部。

           私有的內容只在本類中有效。

私有僅僅是封裝的一種體現而已。


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