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 :私有:是一個權限修飾符,用於修飾成員,不能修飾局部。
私有的內容只在本類中有效。
私有僅僅是封裝的一種體現而已。