面向對象程序設計(簡稱OOP)是當今主流的程序設計范型,它已經取代了20世紀70年代的“結構化”過程化程序設計開發技術。Java是完全面向對象的,必須熟悉OOP才能夠編寫Java程序。面向對象的程序是由對象組成的,每個對象包含對用戶公開的特定功能部分和隱藏的實現部分。
~
本篇主要記錄內容包括:面向對象程序設計概述、靜態域與靜態方法、構造器、內部類。
- 上一篇內容:Java基礎:Java流程控制
- 下一篇內容:Java基礎:Java面向對象
- 更多知識學習:全網最全的 Java 技術棧內容梳理(持續更新中)
文章目錄
- 一、面向對象程序設計概述
- 1、類
- 2、對象
- 3、類之間的關系
- 二、靜態域與靜態方法
- 1、關鍵字static
- 2、關鍵字final
- 3、靜態域與靜態方法
- 三、構造器
- 1、構造方法的特點
- 2、 構造方法的重載
- 3、子父類中的構造方法
- 4、注意事項
- 四、內部類
- 1、內部類概念
- 2、內部類的分類
一、面向對象程序設計概述
面向對象程序設計(簡稱OOP)是當今主流的程序設計范型,它已經取代了20世紀70年代的“結構化”過程化程序設計開發技術。Java是完全面向對象的,必須熟悉OOP才能夠編寫Java程序。面向對象的程序是由對象組成的,每個對象包含對用戶公開的特定功能部分和隱藏的實現部分。
1、類
類(class)是構造對象的模板或藍圖。我們可以將類想象成制作小甜餅的切割機,將對象想象為小甜餅。由類構造(construct)對象的過程稱為創建類的實例(instance)。
用 Java 編寫的所有代碼都位于某個類的內部。標準的 Java 庫提供了幾千個類,可以用于用戶界面設計、日期、日歷和網絡程序設計。盡管如此,還是需要在 Java 程序中創建一些自己的類,以便描述應用程序所對應的問題域中的對象。
2、對象
要想使用 OOP,一定要清楚對象的三個主要特性:
- 對象的行為——可以對對象施加哪些操作,或可以對對象施加哪些方法?
- 對象的狀態——當施加那些方法時,對象如何響應?
- 對象的標識——如何辨別具有相同行為與狀態的不同對象?
同一個類的所有對象實例,由于支持相同的行為而具有家族式的相似性。對象的行為是用可調用的方法定義的。
此外,每個對象都保存著描述當前特征的信息。這就是對象的狀態。對象的狀態可能會隨著時間而發生改變,但這種改變不會是自發的。對象狀態的改變必須通過調用方法實現(如果不經過方法調用就可以改變對象狀態,只能說明封裝性遭到了破壞)。
但是,對象的狀態并不能完全描述一個對象。每個對象都有一個唯一的身份(identity)。例如,在一個訂單處理系統中,任何兩個訂單都存在著不同之處,即使所訂購的貨物完全相同也是如此。需要注意,作為一個類的實例,每個對象的標識永遠是不同的,狀態常常也存在著差異。
對象的這些關鍵特性在彼此之間相互影響著。例如,對象的狀態影響它的行為(如果一個訂單 “已送貨” 或 “已付款”,就應該拒絕調用具有增刪訂單中條目的方法。反過來,如果訂單是 “空的”,即還沒有加入預訂的物品,這個訂單就不應該進入“已送貨”狀態)。
3、類之間的關系
在類之間,最常見的關系有:依賴(uses-a)、聚合(has-a)、繼承(is-a)
-
依賴(dependence),即 “uses-a” 關系,是一種最明顯的、最常見的關系。例如,Order類使用Account類是因為Order對象需要訪問Account對象查看信用狀態。但是Item類不依賴于Account類,這是因為Item對象與客戶賬戶無關。因此,如果一個類的方法操縱另一個類的對象,我們就說一個類依賴于另一個類。
應該盡可能地將相互依賴的類減至最少。如果類A不知道B的存在,它就不會關心B的任何改變(這意味著B的改變不會導致A產生任何bug)。用軟件工程的術語來說,就是讓類之間的耦合度最小。
-
聚合(aggregation),即 “has-a” 關系,是一種具體且易于理解的關系。例如,一個 Order 對象包含一些 Item 對象。聚合關系意味著類 A 的對象包含類B的對象。
-
繼承(inheritance),即 “is-a” 關系,是一種用于表示特殊與一般關系的。例如,Rush Order 類由 Order 類繼承而來。在具有特殊性的 RushOrder 類中包含了一些用于優先處理的特殊方法,以及一個計算運費的不同方法;而其他的方法,如添加商品、生成賬單等都是從 Order 類繼承來的。一般而言,如果類 A 擴展類 B,類 A 不但包含從類 B 繼承的方法,還會擁有一些額外的功能。
二、靜態域與靜態方法
1、關鍵字static
static
關鍵字的主要意義是在于創建獨立于具體對象的域變量或者方法。以致于即使沒有創建對象,也能使用屬性和調用方法!
static
關鍵字的另一個比較關鍵的作用就是用來形成靜態代碼塊以優化程序性能。static
塊可以置于類中的任何地方,類中可以有多個static
塊。在類初次被加載的時候,會按照static
塊的順序來執行每個static
塊,并且只會執行一次。
static 注意事項:
- 靜態內容是優先于對象存在的,只能訪問靜態 。靜態修飾的內容存于內存的靜態區;
main
方法為靜態方法,僅僅為程序執行入口,它不屬于任何一個對象,可以定義在任意類中;- 靜態上下文中,不能引用非靜態的成員變量或成員方法;
- 在靜態上下文中,無法使用
this/super
關鍵字, 因為this/super
指代的是對象
靜態變量和成員變量的區別:
-
所屬不同:靜態變量屬于類,所以也稱為為類變量,成員變量屬于對象,所以也稱為實例變量(對象變量);
-
內存中位置不同:靜態變量存儲于方法區的靜態區,成員變量存儲于堆內存;
-
內存出現時間不同:靜態變量隨著類的加載而加載,隨著類的消失而消失,成員變量隨著對象的創建而存在,隨著對象的消失而消失;
-
調用不同:靜態變量可以通過類名調用,也可以通過對象調用成員變量只能通過對象調用
2、關鍵字final
繼承的出現提高了代碼的復用性,并方便開發。但隨之也有問題,有些類在描述完之后,不想被繼承,或者有些類中的部分方法功能是固定的,不想讓子類重寫。可是當子類繼承了這些特殊類之后,就可以對其中的方法進行重寫,那怎么解決呢?
要解決上述的這些問題,需要使用到一個關鍵字 final
, final
的意思為最終,不可變。 final
是個修飾符,它可以用來修飾 類,類的成員,以及局部變量。
final 特點
final
修飾類不可以被繼承,但是可以繼承其他類;final
修飾的方法不可以被覆蓋,但父類中沒有被final
修飾方法,子類覆蓋后可以加final
;final
修飾的變量稱為常量,這些變量只能賦值一次;final
修飾的引用類型的變量值為對象地址值,地址值不能更改,但是地址內的對象屬性值可以修改;final
修飾成員變量,必須在創建對象前賦值,或在多個構造方法中進行賦值,否則報錯。
3、靜態域與靜態方法
如果將域定義為static,每個類中只有一個這樣的域。而每一個對象對于所有的實例域卻都有自己的一份拷貝。
Ps:在絕大多數的面向對象程序設計語言中,靜態域被稱為類域。術語 “static” 只是沿用了 C++ 的叫法,并無實際意義。
靜態變量使用得比較少,但靜態常量卻使用得比較多。例如,在 Math 類中定義了一個靜態常量:PI。在程序中,可以采用 Math.PI 的形式獲得這個常量。如果關鍵字 static 被省略,PI 就變成了 Math 類的一個實例域。需要通過 Math 類的對象訪問 PI,并且每一個 Math 對象都有它自己的一份 PI 拷貝。
靜態方法是一種不能向對象實施操作的方法。
三、構造器
構造器也被稱為構造方法,是一種特殊的方法,調用構造方法可以創建新對象。構造方法可以執行任何操作,實際應用中,構造方法一般用于初始化操作,例如初始化對象的數據域。
構造方法定義:修飾符 構造方法名 (參數列表){}
1、構造方法的特點
- 構造方法沒有返回類型,包括沒有
void
。,也不需要寫返回值。因為它是為構建對象的,對象創建完,方法就執行結束; - 構造方法名必須和類名保持一致;
- 只有在創建對象的時候自動調用執行,而且只執行一次
2、 構造方法的重載
一個類中可以有多個構造方法,多個構造方法是以重載的形式存在的;
意義在于:可以根據不同的需求,定義不同的構造方法,靈活地初始化對象的成員變量;
構造方法是可以被 private
修飾,作用是:其他程序無法創建該類的對象
3、子父類中的構造方法
在創建子類對象時,父類的構造方法會先執行,因為子類中所有構造方法的第一行有默認的隱式super();
語句,它是用來訪問父類中的空參數構造方法,進行父類成員的初始化操作
this()
是調用本類的構造方法,super()
是調用父類的構造方法, 且兩條語句不能同時存在
4、注意事項
- 每一
class
類都必須有一個構造方法,如果自己不寫,編譯的時候,系統會給出默認構造方法; - 構造方法也是可以重載的;
- 在創建對象時,會調用與參數列表對應的構造方法;
- 子類的所有構造方法,直接或間接必須調用到父類構造方法; 子類的構造方法什么都不寫,默認的構造方法第一行
super()
四、內部類
1、內部類概念
將類寫在其他類的內部,可以寫在其他類的成員位置和局部位置,這時寫在其他類內部的類就稱為內部類。其他類也稱為外部類。在描述事物時,若一個事物內部還包含其他可能包含的事物,比如在描述汽車時,汽車中還包含這發動機,這時發動機就可以使用內部類來描述。
class 汽車 { //外部類class 發動機 { //內部類}
}
內部類的特點:①內部類提供了更好的封裝,只有外部類能訪問內部類;②內部類可以獨立繼承一個接口,不受外部類是否繼承接口影響;③內部類可以直接訪問外部類的成員,包括私有 private
;④健外部類要訪問內部類的成員,必須創建對象;⑤在外部類中,即使內部類中用 private
修飾的成員,也可以在外部類中以 內部類 對象.成員
的方式訪問;⑥private
修飾內部類,則外部類以外不能訪問,只能在外部類訪問。
2、內部類的分類
內部類分為 成員內部類 與 局部內部類其次還有 匿名內部類、靜態內部類:
- 成員內部類:定義在外部類中的成員位置,與類中的成員變量相似,可通過
外部類.對象
進行訪問,訪問方式:外部類名.內部類名 變量名 = new 外部類名().new 內部類名();
。 - 局部內部類:定義在外部類方法中的局部位置。與訪問方法中的局部變量相似,可通過調用方法進行訪問,訪問方式: 在外部類方法中,創建內部類對象,進行訪問。Ps:①局部內部類,只能在方法體中使用;②局部類不能加訪問修飾符,因為它們不是類成員;③局部類可以直接訪問外部類成員;④JDK8或者更高版本,從語法上講,不要求被局部內部類所訪問的局部變量,一定要加
final
,但是,如果在代碼中,沒有final
,只要局部內部類訪問局部變量,編譯器會自動給局部變量加final
。 - 匿名內部類:就是一個沒有名字的局部內部類,匿名內部類是創建某個類型子類對象的快捷方式,沒有名字,意味著,類不能通過名字來復用。不能復用,并不意味著不能使用,它還是可以被使用的,但是只能被使用一次(在類定義的時候使用一次)。Ps:①匿名內部類是沒有訪問修飾符;②匿名內部類必須繼承一個類(可以是 具體類也可以是抽象類) 或者實現一個接口;③匿名內部類中不能存在任何靜態成員或方法;④匿名內部類是沒有構造方法,因為它沒有類名;⑤匿名內部類為局部內部類,所以局部內部類的所有限制同樣對匿名內部類生效;⑥匿名內部類不能是抽象的,所以,它必須要實現繼承的類或者實現的接口的所有抽象方法
- 靜態內部類:使用
static
修飾的成員內部類我們稱之為靜態內部類,靜態內部類的創建是不需要依賴于外部類,可以直接創建,訪問特征:①對于靜態內部類而言,它不能訪問外部類中非靜態的成員變量和成員方法;②在外部類中訪問,靜態內部類,和訪問普通成員內部類沒有任何區別;③在外部類的外部訪問靜態內部類,由于靜態內部類,不依賴于外部類對象 :new 外部類類名.內部類類名()