面向?qū)ο筇匦越榻B(封裝,繼承,多態(tài)),與 C++區(qū)別
面向過程讓計(jì)算機(jī)有步驟地順序做一件事,是過程化思維,使用面向過程語言開發(fā)大型項(xiàng)目,軟件復(fù)用和維護(hù)存在很大問題,模塊之間耦合嚴(yán)重。面向?qū)ο笙鄬?duì)面向過程更適合解決規(guī)模較大的問題,可以拆解問題復(fù)雜度,對(duì)現(xiàn)實(shí)事物進(jìn)行抽象并映射為開發(fā)對(duì)象,更接近人的思維。例如開門這個(gè)動(dòng)作,面向過程是 open(Door door),動(dòng)賓結(jié)構(gòu),door 作為操作對(duì)象的參數(shù)傳入方法,方法內(nèi)定義開門的具體步驟。面向?qū)ο蟮姆绞绞紫葧?huì)定義一個(gè)類 Door,抽象出門的屬性(如尺寸、顏色)和行為(如 open 和 close),主謂結(jié)構(gòu)。面向過程代碼松散,強(qiáng)調(diào)流程化解決問題。面向?qū)ο蟠a強(qiáng)調(diào)高內(nèi)聚、低耦合,先抽象模型定義共性行為,再解決實(shí)際問題。
封裝:把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對(duì)象操作,對(duì)不可信的進(jìn)行信息隱藏。封裝是面向?qū)ο蟮奶卣髦唬菍?duì)象和類概念的主要特性。簡單的說,一個(gè)類就是一個(gè)封裝了數(shù)據(jù)以及操作這些數(shù)據(jù)的代碼的邏輯實(shí)體。在一個(gè)對(duì)象內(nèi)部,某些代碼或某些數(shù)據(jù)可以是私有的,不能被外界訪問。通過這種方式,對(duì)象對(duì)內(nèi)部數(shù)據(jù)提供了不同級(jí)別的保護(hù),以防止程序中無關(guān)的部分意外的改變或錯(cuò)誤的使用了對(duì)象的私有部分。
繼承:是指可以讓某個(gè)類型的對(duì)象獲得另一個(gè)類型的對(duì)象的屬性的方法。它支持按級(jí)分類的概念。繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對(duì)這些功能進(jìn)行擴(kuò)展。通過繼承創(chuàng)建的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。要實(shí)現(xiàn)繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實(shí)現(xiàn)。繼承概念的實(shí)現(xiàn)方式有二類:實(shí)現(xiàn)繼承與接口繼承。實(shí)現(xiàn)繼承是指直接使用基類的屬性和方法而無需額外編碼的能力;接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實(shí)現(xiàn)的能力;
多態(tài):是指一個(gè)類實(shí)例的相同方法在不同情形有不同表現(xiàn)形式。多態(tài)機(jī)制使具有不同內(nèi)部結(jié)構(gòu)的對(duì)象可以共享相同的外部接口。這意味著,雖然針對(duì)不同對(duì)象的具體操作不同,但通過一個(gè)公共的類,它們(那些操作)可以通過相同的方式予以調(diào)用。
與 C++的共同點(diǎn):C++和 Java 都是強(qiáng)類型語言,都有類的概念,并且都有 private、protected、public 關(guān)鍵字來限定屬性、方法的訪問權(quán)限。
與 C++的區(qū)別:
(1)封裝的區(qū)別:C++和 Java 的 private、protected、public 表示的權(quán)限范圍不同。C++中,private 表示只能在類自己的方法中訪問;protected 表示類自己和類的子類可以訪問;public 表示任何地方均可訪問。Java 中,private 表示類自己的方法中訪問;protected 表示類自己和類的子類;public 表示任何地方均可以訪問;不加任何限定字表示同一包下的其他類可以訪問。
(2)繼承的區(qū)別
C++的繼承方式

Java 只保留了 public 繼承的這種繼承方式,從替換原則的角度來說,這樣實(shí)際上更符合面向?qū)ο蟮乃枷搿++可以繼承多個(gè)類,繼承之后就擁有了所有子類的屬性和方法。Java 只能繼承自一個(gè)類,但可以實(shí)現(xiàn)多個(gè)接口。
另外 Java 語言本身除了提供了 Java 語法外,還和 Java 標(biāo)準(zhǔn)庫進(jìn)行了高度的結(jié)合,所有的 Java類,都是 Object 類的子類。并且不需要程序員顯示的繼承 Object 類,編譯機(jī)默認(rèn)所有類均直接或間接的繼承自 Object 類。所以說 Java 是單根繼承的。
不管是 C++和 Java,為了實(shí)現(xiàn)多態(tài),都需要將對(duì)象的方法進(jìn)行晚綁定,即在運(yùn)行時(shí)決定調(diào)用對(duì)象的哪一個(gè)方法,而不是在編譯期間確定。C++方法的晚綁定是通過虛函數(shù)實(shí)現(xiàn)。虛函數(shù)又分為純虛函數(shù)和虛函數(shù),定義純虛函數(shù)的類可以不實(shí)現(xiàn)它,而交給子類區(qū)實(shí)現(xiàn),定義虛函數(shù)的類需要同時(shí)實(shí)現(xiàn)它。無論是虛函數(shù)還是純虛函數(shù),編譯器在編譯時(shí),不會(huì)直接決定該執(zhí)行哪一個(gè)函數(shù),而是通過虛函數(shù)表中的函數(shù)指針去調(diào)用。如此實(shí)現(xiàn)了對(duì)象方法調(diào)用的晚綁定。Java 的除了 private 方法和 static 之外的所有方法均為晚綁定,所以 Java 中沒有虛函數(shù)的概念。
多態(tài)的分類:編譯時(shí)多態(tài)(靜態(tài)多態(tài),重載)和運(yùn)行時(shí)多態(tài)(動(dòng)態(tài)多態(tài))
多態(tài)的實(shí)現(xiàn)方法:子類繼承父類(extends)和類實(shí)現(xiàn)接口(implements) 多態(tài)的實(shí)現(xiàn)原理:Java 的方法調(diào)用方式:Java 的方法調(diào)用有兩類,動(dòng)態(tài)方法調(diào)用與靜態(tài)方法調(diào)用。靜態(tài)方法調(diào)用是指對(duì)于類的靜態(tài)方法的調(diào)用方式,是靜態(tài)綁定的;而動(dòng)態(tài)方法調(diào)用需要有方法調(diào)用所作用的對(duì)象,是動(dòng)態(tài)綁定的。類調(diào)用(invokestatic) 是在編譯時(shí)刻就已經(jīng)確定好具體調(diào)用方法的情況,而實(shí)例調(diào)用invokevirtual) 則是在調(diào)用的時(shí)候才確定具體的調(diào)用方法,這就是動(dòng)態(tài)綁定,也是多態(tài)要解決的核心問題。
JVM 的方法調(diào)用指令有四個(gè),分別是 invokestatic,invokespecial,invokesvirtual 和 invokeinterface。前兩個(gè)是靜態(tài)綁定,后兩個(gè)是動(dòng)態(tài)綁定的。本文也可以說是對(duì)于 JVM 后兩種調(diào)用實(shí)現(xiàn)的考察。
常量池(constant pool):常量池中保存的是一個(gè) Java 類引用的一些常量信息,包含一些字符串常量及對(duì)于類的符號(hào)引用信息等。Java 代碼編譯生成的類文件中的常量池是靜態(tài)常量池,當(dāng)類被載入到虛擬機(jī)內(nèi)部的時(shí)候,在內(nèi)存中產(chǎn)生類的常量池叫運(yùn)行時(shí)常量池。常量池在邏輯上可以分成多個(gè)表,每個(gè)表包含一類的常量信息,本文只探討對(duì)于 Java 調(diào)用相關(guān)的常量池表。
方法表與方法調(diào)用:方法表是動(dòng)態(tài)調(diào)用的核心,也是 Java 實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的主要方式。它被存儲(chǔ)于方法區(qū)中的類型信息,包含有該類型所定義的所有方法及指向這些方法代碼的指針,注意這些具體的方法代碼可能是被覆寫的方法,也可能是繼承自基類的方法。
