Java學習之面向對象一
1 面向對象
1.1 理解什麽是面向過程、面向對象
面向過程與面向對象都是我們編程中,編寫程序的一種思維方式。
l 面向過程的程序設計方式,是遇到一件事時,思考“我該怎麽做”,然後一步步實現的過程。
例如:公司打掃衛生(擦玻璃、掃地、拖地、倒垃圾等),按照面向過程的程序設計方式會思考“打掃衛生我該怎麽做,然後一件件的完成”,最後把公司衛生打掃幹凈了。
l 面向對象的程序設計方式,是遇到一件事時,思考“我該讓誰來做”,然後那個“誰”就是對象,他要怎麽做這件事是他自己的事,反正最後一群對象合力能把事就好就行了。
例如,公司打掃衛生(擦玻璃、掃地、拖地、倒垃圾等),按照面向對象的程序設計方式會思考“我該讓誰來做,如小明擦玻璃、讓小麗掃地、讓小郭拖地、讓小強倒垃圾等”,這裏的“小明、小麗、小郭、小強”就是對象,他們要打掃衛生,怎麽打掃是他們自己的事,反正最後一群對象合力把公司衛生打掃幹凈了。
1.2 面向對象舉例
l 買電腦(組裝機)
先使用面向過程說明買電腦這件事:假如我們需要買組裝電腦,這時首先會在網上查詢具體每一個硬件的參數和報價。然後會去電腦城進行多家詢價,接著詢價結束後回家根據具體的結果分析出自己比較滿意的哪家報價,接著會到這家店裏進行組裝,組裝時還需要進行現場監督,組裝完成安裝相應的系統,然後電腦抱回家。
分析上述整個過程大體分一下幾步:上網查詢參數和報價、電腦城詢價、現場安裝和監督、抱電腦回家。在整個過程中我們參與了每一個細節,並且會感覺相當累。
使用面向對象說明買電腦這件事:假如我們需要買組裝機,這時應該找一個懂電腦硬件的人,讓他幫我們查看參數和報價,並進行詢價和殺價,以及現場組裝監督。而我們自己並不需要親歷親為具體怎麽做,只要告訴這個人我們想要的具體需求即可。
分析上述整個過程,發現瞬間變的十分輕松,只要找到懂電腦硬件的這個人,我們的問題都可以解決。並且在這個過程中我們不用那麽辛苦。
1.3 面向對象思維方式的好處
通過生活中的真實場景使用面向對象分析完之後,我們開始分析面向過程和面向對象的差異做出總結:
l 面向對象思維方式是一種更符合人們思考習慣的思想
l 面向過程思維方式中更多的體現的是執行者(自己做事情),面向對象中更多的體現是指揮者(指揮對象做事情)。
l 面向對象思維方式將復雜的問題簡單化。
2 類與對象
2.1 對象在需求中的使用
對面向對象有了了解之後,我們來說說在具體問題中如何使用面向對象去分析問題,和如何使用面向對象。
我們把大象裝冰箱為例進行分析。
在針對具體的需求,可以使用名詞提煉的辦法進行分析,尋找具體的對象。
需求:把大象裝冰箱裏
對象:大象、冰箱
分三步:
1、打開冰箱門
2、將大象裝進去
3、關閉冰箱門
分析發現打開、裝、關閉都是冰箱的功能。即冰箱對象具備如下功能:
冰箱打開
冰箱存儲
冰箱關閉
用偽代碼描述,上述需求中有兩個具體的事物 大象 和 冰箱
描述大象:
class 大象
{
}
描述冰箱
class冰箱
{
void 打開(){}
void 存儲(大象){}
void 關閉(){}
}
當把具體的事物描述清楚之後,需要使用這些具體的事物,Java使用具體的事物,需要通過new關鍵字來創建這個事物的具體實例。
使用對象:
1、創建冰箱的對象
冰箱 bx = new 冰箱();
2、調用冰箱的功能
對象.功能();
bx.打開();
bx.存儲(new 大象());
bx.關閉();
l 總結:
1、先按照名詞提煉問題領域中的對象
2、對對象進行描述,其實就是在明確對象中應該具備的屬性和功能
3、通過new的方式就可以創建該事物的具體對象
4、通過該對象調用它以後的功能。
2.2 對象在代碼中的體現
在分析現實生活中的事物時發現,這些事物都有其具體的特點和功能,這些特點和功能就組成了這個特殊的事物。
描述小汽車。
分析:
事物的特點(屬性):
顏色。
輪胎個數。
事物的(功能):
運行。
發現:事物其實就是由特點(屬性)和行為(功能)組成的。
可以簡單理解:屬性就是數值,其實就是變量;行為就是功能,就是方法。
小汽車 {
顏色;
輪胎個數;
運行() { }
}
通過計算機語言Java來描述這個事物。
l 定義類的格式
public class 類名 {
//可編寫0至n個屬性
數據類型 變量名1;
數據類型 變量名2;
//可編寫0至n個方法
修飾符 返回值類型 方法名(參數){
執行語句;
}
}
l 汽車類
public class Car {
String color;
int number;
void run() {
System.out.println(color + ":" + number);
}
}
通過代碼的描述,知道類的真正意義就是在描述事物。屬性和功能統稱為事物中的成員。
事物的成員分為兩種:成員屬性和成員功能。
成員屬性在代碼中的體現就是成員變量
成員功能在代碼中的體現就是成員方法
把寫好的代碼測試一下。需要一個可以獨立運行類。
l 創建對象的格式:
類名 對象名 = new 類名();
l 測試類
public class CarDemo {
public static void main(String[] args) {
/*
* 測試:Car類中的run方法。
*/
// 1,創建Car的對象。給對象起個名字。
Car c = new Car();// c是類類型的變量。c指向了一個具體的Car類型的對象。
// 2,通過已有的對象調用該對象的功能。格式:對象.對象成員;
// 3,可以該對象的屬性賦值。
c.color = "red";
c.number = 4;
c.run();
}
}
2.3 對象的內存圖解
經過上面對小汽車的描述,和Java代碼測試,我們雖然可以將生活中的事物使用Java代碼描述出來,但是這些代碼在內存中是如何執行的,接下來我們需要研究下對象在內存的圖解。
接下來就是分析對象在內存中的分配情況。這裏需要畫圖一步一步演示,嚴格按照畫圖流程講解內存對象創建過程。
2.4 類和對象的區別
面向對象的編程思想力圖在程序中對事物的描述與該事物在現實中的形態保持一致。為了做到這一點,面向對象的思想中提出兩個概念,即類和對象。其中,類是對某一類事物的抽象描述,而對象用於表示現實中該類事物的個體。接下來通過一個圖例來抽象描述類與對象的關系,如下圖所示。
圖1-1 類與對象
在上圖中,可以將玩具模型看作是一個類,將一個個玩具看作對象,從玩具模型和玩具之間的關系便可以看出類與對象之間的關系。類用於描述多個對象的共同特征,它是對象的模板。對象用於描述現實中的個體,它是類的實例。從上圖中可以明顯看出對象是根據類創建的,並且一個類可以對應多個對象,接下來分別講解什麽是類和對象。
經過前面幾個知識點的學習,基本上掌握了類是用於描述事物的,類中可以定義事物的屬性和行為。而對象是通過描述的這個類,使用new關鍵字創建出來,通過對象就可以調用該對象具體的屬性和功能了。
2.5 局部變量和成員變量區別
理解清楚了類和對象之後,結合前5天的學習知識,發現在描述類的屬性和前面學習定義變量差別不大,唯一區別就是位置發生了改變,那麽類中定義的變量,和在方法定義的變量有啥差別呢?
回憶以前學習時變量的定義方式,和位置,以及現在定義類中屬性的特點。總結下面幾點異同
區別一:定義的位置不同
定義在類中的變量是成員變量
定義在方法中或者{}語句裏面的變量是局部變量
區別二:在內存中的位置不同
成員變量存儲在對內存的對象中
局部變量存儲在棧內存的方法中
區別三:聲明周期不同
成員變量隨著對象的出現而出現在堆中,隨著對象的消失而從堆中消失
局部變量隨著方法的運行而出現在棧中,隨著方法的彈棧而消失
區別四:初始化不同
成員變量因為在堆內存中,所有默認的初始化值
局部變量沒有默認的初始化值,必須手動的給其賦值才可以使用。
2.6 基本類型和引用類型作為參數傳遞
引用類型數據和基本類型數據作為參數傳遞有沒有差別呢?我們用如下代碼進行說明,並配合圖解讓大家更加清晰
class Demo { public static void main(String[] args) { int x = 4; show(x); System.out.println("x="+x); } public static void show(int x) { x = 5;
} } |
基本類型作為參數傳遞時,其實就是將基本類型變量x空間中的值復制了一份傳遞給調用的方法show(),當在show()方法中x接受到了復制的值,再在show()方法中對x變量進行操作,這時只會影響到show中的x。當show方法執行完成,彈棧後,程序又回到main方法執行,main方法中的x值還是原來的值。
class Demo { int x ; public static void main(String[] args) {
Demo d = new Demo(); d.x = 5; show(d); System.out.println("x="+d.x); } public static void show(Demo d) { d.x = 6; } } |
當引用變量作為參數傳遞時,這時其實是將引用變量空間中的內存地址(引用)復制了一份傳遞給了show方法的d引用變量。這時會有兩個引用同時指向堆中的同一個對象。當執行show方法中的d.x=6時,會根據d所持有的引用找到堆中的對象,並將其x屬性的值改為6.show方法彈棧。
由於是兩個引用指向同一個對象,不管是哪一個引用改變了引用的所指向的對象的中的值,其他引用再次使用都是改變後的值。
3 封裝
3.1 封裝概述
提起封裝,大家並不陌生。前面我們學習方法時,就提起過,將具體功能封裝到方法中,學習對象時,也提過將方法封裝在類中,其實這些都是封裝。
封裝,它也是面向對象思想的特征之一。面向對象共有三個特征:封裝,繼承,多態。接下來我們具體學習封裝。
l 封裝表現:
n 1、方法就是一個最基本封裝體。
n 2、類其實也是一個封裝體。
l 從以上兩點得出結論,封裝的好處:
n 1、提高了代碼的復用性。
n 2、隱藏了實現細節,還要對外提供可以訪問的方式。便於調用者的使用。這是核心之一,也可以理解為就是封裝的概念。
n 3、提高了安全性。
3.2 封裝舉例
機箱:
一臺電腦,它是由CPU、主板、顯卡、內存、硬盤、電源等部件組長,其實我們將這些部件組裝在一起就可以使用電腦了,但是發現這些部件都散落在外面,很容造成不安全因素,於是,使用機箱殼子,把這些部件都裝在裏面,並在機箱殼上留下一些插口等,若不留插口,大家想想會是什麽情況。
總結:機箱其實就是隱藏了辦卡設備的細節,對外提供了插口以及開關等訪問內部細節的方式。
3.3 私有private
了解到封裝在生活的體現之後,又要回到Java中,細說封裝的在Java代碼中的體現,先從描述Person說起。
描述人。Person
屬性:年齡。
行為:說話:說出自己的年齡。
class Person {
int age;
String name;
public void show() {
System.out.println("age=" + age + ",name" + name);
}
}
public class PersonDemo {
public static void main(String[] args) {
// 創建Person對象
Person p = new Person();
p.age = -20; // 給Person對象賦值
p.name = "人妖";
p.show(); // 調用Person的show方法
}
}
通過上述代碼發現,雖然我們用Java代碼把Person描述清楚了,但有個嚴重的問題,就是Person中的屬性的行為可以任意訪問和使用。這明顯不符合實際需求。
可是怎麽才能不讓訪問呢?需要使用一個Java中的關鍵字也是一個修飾符 private(私有,權限修飾符)。只要將Person的屬性和行為私有起來,這樣就無法直接訪問。
class Person {
private int age;
private String name;
public void show() {
System.out.println("age=" + age + ",name" + name);
}
}
年齡已被私有,錯誤的值無法賦值,可是正確的值也賦值不了,這樣還是不行,那腫麽辦呢?按照之前所學習的封裝的原理,隱藏後,還需要提供訪問方式。只要對外提供可以訪問的方法,讓其他程序訪問這些方法。同時在方法中可以對數據進行驗證。
一般對成員屬性的訪問動作:賦值(設置 set),取值(獲取 get),因此對私有的變量訪問的方式可以提供對應的 setXxx或者getXxx的方法。
class Person {
// 私有成員變量
private int age;
private String name;
// 對外提供設置成員變量的方法
public void setAge(int a) {
// 由於是設置成員變量的值,這裏可以加入數據的驗證
if (a < 0 || a > 130) {
System.out.println(a + "不符合年齡的數據範圍");
return;
}
age = a;
}
// 對外提供訪問成員變量的方法
public void getAge() {
return age;
}
}
l 總結:
類中不需要對外提供的內容都私有化,包括屬性和方法。
以後再描述事物,屬性都私有化,並提供setXxx getXxx方法對其進行訪問。
l 註意:私有僅僅是封裝的體現形式而已。
3.4 this關鍵字
3.4.1 成員變量和局部變量同名問題
當在方法中出現了局部變量和成員變量同名的時候,那麽在方法中怎麽區別局部變量成員變量呢?可以在成員變量名前面加上this.來區別成員變量和局部變量
class Person {
private int age;
private String name;
public void speak() {
this.name = "小強";
this.age = 18;
System.out.println("name=" + this.name + ",age=" + this.age);
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
p.speak();
}
}
3.4.2 對象的內存解釋
我們已經學習了如何把生活中的事物使用Java代碼描述,接下來我們分析對象在內存中的分配情況。這裏需要畫圖一步一步演示,嚴格按照畫圖流程講解內存對象創建使用過程。
class Person {
private int age;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
p.setAge(30);
System.out.println("大家好,今年我" + p.getAge() + "歲");
}
}
下圖為程序中內存對象的創建使用過程。
圖1-2 內存對象創建使用過程
程序執行流程說明:
1、 先執行main方法(壓棧),執行其中的 Person p = new Person();
2、 在堆內存中開辟空間,並為其分配內存地址0x1234,緊接著成員變量默認初始化(age = 0);將內存地址0x1234賦值給棧內中的Person p 變量
3、 繼續執行p.setAge(30)語句,這時會調用setAge(int age)方法,將30賦值為setAge方法中的“age”變量;執行this.age = age語句,將age變量值30 賦值給成員變量this.age為30;
4、 setAge()方法執行完畢後(彈棧),回到main()方法,執行輸出語句System.out.println(),控制臺打印p對象中的age年齡值。
l 註意:
n this到底代表什麽呢?this代表的是對象,具體代表哪個對象呢?哪個對象調用了this所在的方法,this就代表哪個對象。
n 上述代碼中的 p.setAge(30)語句中,setAge(int age)方法中的this代表的就是p對象。
3.4.3 this的應用
學習this的用法之後,現在做個小小的練習。
需求:在Person類中定義功能,判斷兩個人是否是同齡人
class Person {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
// 判斷是否為同齡人
public boolean equalsAge(Person p) {
// 使用當前調用該equalsAge方法對象的age和傳遞進來p的age進行比較
// 由於無法確定具體是哪一個對象調用equalsAge方法,這裏就可以使用this來代替
/*
* if(this.age == p.age) { return true; } return false;
*/
return this.age == p.age;
}
}
Java學習之面向對象一