面向?qū)ο笫?Java 最重要的特性。Java 是徹底的、純粹的面向?qū)ο笳Z言,在 Java 中“一切都是對象”。本章將介紹面向?qū)ο蠡A(chǔ)知識。
面向?qū)ο?/p>
- 相對面向過程而言, 面向?qū)ο蠛兔嫦蜻^程都是一種思想
- 將功能封裝進對象,強調(diào)具備了功能的對象。
- 是一種符合人們思考習慣的思想, 可以將復雜的事情簡單化, 將程序員從執(zhí)行者轉(zhuǎn)換成了指揮者.
面向?qū)ο蟮拈_發(fā)過程: 其實就是不斷的創(chuàng)建對象,使用對象,指揮對象做事情。
面向?qū)ο蟮脑O(shè)計過程: 其實就是在管理和維護對象之間的關(guān)系。
面向?qū)ο蟮奶卣鳎?/p>
- 封裝(encapsulation): 封裝能夠使外部訪問者不能隨意存取對象的內(nèi)部數(shù)據(jù),隱藏了對象的內(nèi)部細節(jié),只保留有限的對外接口。外部訪問者不用關(guān)心對象的內(nèi)部細節(jié),使得操作對象變得簡單。
- 繼承(inheritance)
- 多態(tài)(polymorphism): 指在父類中成員變量和成員方法被子類繼承之后,可以具有不同的狀態(tài)或表現(xiàn)行為。
什么是類
Java中用類 Class 來描述事物.是具體事物的抽象,概念上的定義。
- 屬性:對應類中的成員變量。
- 行為:對應類中的成員函數(shù)。
類定義包括類聲明和類體兩部分,類定義的語法格式如下:
[public][abstract|final] class className [extends superclassName] [implements interfaceNameList] {類體}
對象的創(chuàng)建
創(chuàng)建對象及訪問對象成員
- 聲明對象與聲明普通變量沒有區(qū)別 ,格式為
type objectName;
聲明對象并不為對象分配內(nèi)存空間,而只是未存儲對象的地址分配內(nèi)存空間 - 實例化對象。分為兩個階段:為對象分配內(nèi)存空間和初始化對象,首先使用new運算符為對象分配內(nèi)存空間,然后再調(diào)用構(gòu)造方法初始化對象。格式如下:
new 類的構(gòu)造方法(); - 通過引用變量訪問對象成員
- 引用變量名.屬性
- 引用變量名.方法名(實參表)
什么是方法
方法聲明
修飾符 1 修飾符2... 返回值類型 方法名(形參表) [ throws 異常列表 ] { }
其中返回值是方法在操作完成后返還調(diào)用它的環(huán)境的數(shù)據(jù),形式有2種:
- return 表達式; // 方法返回結(jié)果為表達式的值;
- return; // 用于無返回值的方法退出,無返回值末尾可不寫;
參數(shù)傳遞
- 基本數(shù)據(jù)類型的參數(shù)傳遞是以傳值的方式進行,即將實際參數(shù)的值傳遞給形參; 在方法內(nèi)對形參的修改只影響形參單元,不影響實參
- 引用類型(如對象、數(shù)組等)參數(shù)傳遞是按地址進行傳遞的。在方法內(nèi)對形參的訪問實際是訪問所指引用對象
方法的特點:
將功能代碼進行封裝,便于對該功能進行調(diào)用。只有被調(diào)用才被執(zhí)行,提高了代碼的復用性. (注意不能在函數(shù)的內(nèi)部定義方法) 。
方法的重載(Overload):
- 在同一個類中,允許存在一個以上的同名函數(shù),函數(shù)參數(shù)個數(shù)或類型至少其一不同.
- 由于只考慮參數(shù)類型和個數(shù)的差異 ,不考慮出現(xiàn)返回值類型的差異. 因為這將導致算法的不確定性,這是不可能存在的。強烈建議重載其返回值類型相同。
- 方法調(diào)用的匹配處理原則是,首先按“精確匹配”原則去查找匹配方法,如果找不到,則按“自動類型轉(zhuǎn)換匹配”原則去查找能匹配的方法。
- 所謂“精確匹配”就是實參和形參類型完全一致
- 所謂“自動轉(zhuǎn)換匹配”是指雖然實參和形參類型不同,但能將實參的數(shù)據(jù)按自動轉(zhuǎn)換原則賦值給形參。
mybatis 的 SQL 操作方法簽名不支持重載。
方法的覆蓋(Override)
- 方法名、參數(shù)列表、完全相同才會產(chǎn)生方法覆蓋;
- 返回類型通常也要一致,只有返回類型為引用類型時,允許子類方法的返回類型是父類方法返回類型的子類型。
- 覆蓋不能改變方法的靜態(tài)與非靜態(tài)屬性。子類中不能將父類非靜態(tài)方法定義為靜態(tài)方法,反之也一樣。
- final 方法不能被覆蓋。
不允許子類方法的訪問修飾符比父類有更多的限制。例如:子類不能將父類的 public 方法定義為 protected 方法。但可以將父類的 private 方法在子類中重新定義為 public 方法.通常將子類方法訪問修飾符與父類保持一致.
構(gòu)造方法
作用: 給對象進行初始化
構(gòu)造方法的特點
- 構(gòu)造方法的名稱必須與類名同名;
- 構(gòu)造方法沒有返回類型, 包括void, 所以不可以寫return語句;
- 構(gòu)造方法只能與 new 運算符結(jié)合使用;
- 通常一個類可提供多個構(gòu)造方法,這些方法的參數(shù)不同。在創(chuàng)建對象
時,系統(tǒng)自動調(diào)用參數(shù)匹配的構(gòu)造方法為對象初始化 - 如果一個類未指定構(gòu)造方法,則系統(tǒng)自動提供的無參構(gòu)造方法,但如果自定義了構(gòu)造方法,則系統(tǒng)不再提供無參構(gòu)造方法。
無參構(gòu)造方法形式如下: public Person() { } , 所以自己最好還要默默的加入無參構(gòu)造方法 - 什么時候定義構(gòu)造方法: 當分析事物時, 該事物具備一定特性或行為, 可以將這些內(nèi)容定義在構(gòu)造方法中.
一個類默認有一個空參數(shù)的構(gòu)造函數(shù),這個構(gòu)造函數(shù)的權(quán)限與所屬類一致. 如果類被 public 修飾,則默認的構(gòu)造函數(shù)也被 public 修飾.總之默認構(gòu)造函數(shù)的權(quán)限是隨著類而變化.
對象的初始化和構(gòu)造方法
在創(chuàng)建對象時,要給對象的屬性成員分配內(nèi)存空間,同時進行初始化。
- 如果定義屬性成員時沒有指定初值,則系統(tǒng)自動指定初值.在定義屬性成員時也可以指定初值.public class Point { private int x=10; ……
- 指定初值的另一種辦法是通過初始化塊來設(shè)置對象的初值(也叫做構(gòu)造代碼塊,它是給所有對象進行統(tǒng)一初始化)。
// 注意首先是按照屬性定義的初值,然后是初始化塊, - 最后是構(gòu)造方法:構(gòu)造方法是給對相關(guān)設(shè)置初值的規(guī)范方法,構(gòu)造方法是根據(jù)方法參數(shù)給對象屬性賦不同的值
成員變量
聲明類體中成員變量語法格式如下:
[public | protected | private ] [static] [final] type variableName; //成員變量
成員方法
[public | protected | private ] [static] [final | abstract] [native] [synchronized] type methodName([paramList]) [throws exceptionList] { //方法體 }
static關(guān)鍵字
靜態(tài)屬性
用 static 修飾的屬性是屬于類的靜態(tài)屬性, 相應的成員變量為類變量
- 類變量的訪問形式
- 在本類中直接訪問:count
- 通過類名訪問:User.count
- 不建議通過類的一個對象訪問,如:x1.count, 實際上還是通過類名的方式訪問
- 給類變量賦初值
默認賦值即可,也可以用靜態(tài)初始化代碼塊 static{count=100;}
// 靜態(tài)初始化代碼的執(zhí)行是在main方法執(zhí)行前完成。 - 被 static 修飾的類成員特點:是共享數(shù)據(jù), 隨著類的加載而加載, 優(yōu)先于對象存在, 被所有對象所共享, 可以直接被類名調(diào)用.
靜態(tài)方法
用 static 修飾的方法稱為靜態(tài)方法,也叫類方法. 在 static 方法中只能處理類變量,也可訪問其它 static 方法,但不能訪問任何歸屬對象空間的變量或方法.
而非靜態(tài)成員變量和方法卻可以訪問靜態(tài)資源.
- 靜態(tài)方法中不可以寫 this,super 關(guān)鍵字
- 主函數(shù)是靜態(tài)方法.
tip: 創(chuàng)建某個工具類, 可只提供相應的靜態(tài)方法, 進一步為了讓某個類不能創(chuàng)建對象, 可以私有化構(gòu)造函數(shù).
理解 this 和 super
出現(xiàn)在類的實例方法或構(gòu)造方法中,this 代表所在函數(shù)所屬對象的引用。用 this 作前綴可訪問當前對象的實例變量或成員方法.
- this.實例變量; // 能加 this 則盡量加, 這樣代碼更清晰
- this.成員方法; // 本類成員方法的調(diào)用, 能加 this 則盡量加 this
- this(參數(shù)),用來調(diào)用同類其他構(gòu)造方法.注意 this 語句只能定義在構(gòu)造函數(shù)的第一行,因為初始化要先執(zhí)行.
super關(guān)鍵字則和 this 差不多,都是一個引用指向自身和上一級父類罷了.
this()構(gòu)造的此類用法, 可以減少構(gòu)造的一些重復代碼
public Msg() {
this(0, null, -1);
}
public Msg(int no) {
this(no, null);
}
public Msg(int no, String str) {
this(no, str);
}
對象初始化過程總結(jié)
- new 用到了class 文件, 所以先會找到 class文件并加載到內(nèi)存
- 執(zhí)行類的static {}代碼塊
- 在堆內(nèi)存中開辟空間,分配內(nèi)存地址
- 在堆內(nèi)存中建立對象的特有屬性, 并默認初始化
- 對屬性顯示初始化;
- 構(gòu)造代碼塊初始化{};
- 構(gòu)造函數(shù)初始化;
- 將內(nèi)存地址賦給棧內(nèi)存變量.
所以加載順序中: 屬性顯示初始化 早于 構(gòu)造代碼塊初始化 早于 構(gòu)造函數(shù)初始化
與之類似, 靜態(tài)屬性顯示初始化 早于 靜態(tài)構(gòu)造代碼塊初始化
代碼的組織形式-使用包
在 Java 中為了防止類、接口、枚舉和注釋等命名沖突引用了包(package)概念,包本質(zhì)上命名空間(namespace)。在包中可以定義一組相關(guān)的類型(類、接口、枚舉和注釋),并為它們提供訪問保護和命名空間管理。
package 語句定義包,package 語句應該放在源文件的第一行,在每個源文件中只能有一個包定義語句,并且 package 語句適用于所有類型(類、接口、枚舉和注釋)的文件。定義包語法格式如下:package pkg1[.pkg2[.pkg3…]];
Java API簡介: Java 中按包來組織類.包的組織采用分層結(jié)構(gòu),與文件系統(tǒng)中的目錄的組織對應一致.通常將邏輯相關(guān)的類放在同一個包中。
包將類的命名空間進行有效劃分,同一包中不能有兩個同名的類. Java 系統(tǒng)提供的類庫也成為Java API, 是系統(tǒng)提供的已實現(xiàn)的標準類的集合。
建立包
創(chuàng)建包就是在指定目錄路徑下創(chuàng)建一個子文件夾,這個包中所有類的字節(jié)碼文件將存放在該文件夾下。
方法1: 創(chuàng)建一個 test 子目錄,將源程序文件存放到該目錄,在該目錄下利用javac編譯源代碼,或者在別處編譯完程序后將字節(jié)碼文件拷貝到該目錄即可。
方法2: 采用帶路徑指示的編譯命令: 格式:javac –d destpath Point.java
編譯器將自動在 destpath 指定的目錄下建一個test子目錄,并將產(chǎn)生的字節(jié)碼文件保存到該子目錄下 。典型用法是源程序放在當前目錄下, 用如下命令編譯 javac –d . Point.java 。編譯后將在當前目錄自動創(chuàng)建 test 子目錄
包的引用
同一個包下的類之間互相引用是不需要包名的,可以直接使用。但如果類不在同一個包內(nèi),則必須要知道其所在的包。
- 使用類的完全限定名 :new java.util.Date()
- 用 import 語句加載需要使用的類。例: import java.util.Date; 然后在程序中可以直接通過類名創(chuàng)建對象, 如:new Date(); 用 import 語句加載整個包, 用
*號代替類名位置。 它將加載包中的所有的類。例:import java.util.*; - 使用靜態(tài)導入,它有一個 static 關(guān)鍵字,可以直接導入類的公開靜態(tài)方法和成員。例:
import static java.util.Arrays.*;。但是注意靜態(tài)導入不應過度使用,否則難以區(qū)分訪問的是哪個類的代碼。
封裝性與訪問控制
Java 面向?qū)ο蟮姆庋b性是通過對成員變量和方法進行訪問控制實現(xiàn)的,訪問控制分為4個等級:私有、默認、保護和公有

- 公有級別的關(guān)鍵字是 public,公有級別的成員變量和方法可以在任何場合被直接訪問,是最寬松的一種訪問控制等級。
- 保護級別的關(guān)鍵字是 protected,保護級別在同一包中完全與默認訪問級別一樣,但是不同包中子類能夠繼承父類中的 protected 變量和方法,這就是所謂的保護級別,“保護”就是保護某個類的子類都能繼承該類的變量和方法。
- 默認級別沒有關(guān)鍵字,也就是沒有訪問修飾符,默認級別的成員變量和方法,可以在其所在類內(nèi)部和同一個包的其他類中被直接訪問,但在不同包的類中則不允許直接訪問。
- 私有級別的關(guān)鍵字是 private,私有級別的成員變量和方法只能在其所在類的內(nèi)部自由使用,在其他的類中則不允許直接訪問。
提示 訪問類成員時,在能滿足使用的前提下,應盡量限制類中成員的可見性,訪問級別順序是:私有級別→默認級別→保護級別→公有級別。
Jar 包
為方便使用第三方代碼,也為了方便我們寫的代碼給其他人使用,各種程序語言大多有打包的概念,打包的一般不是源代碼,而是編譯后的代碼。打包將多個編譯后的文件打包為一個文件,方便其他程序調(diào)用。
在Java中,編譯后的一個或多個包的Java class文件可以打包為一個文件,Java中打包命令為jar,打包后的文件擴展名為.jar,一般稱之為jar包。
可以使用如下方式打包,首先到編譯后的java class文件根目錄,然后運行如下命令:
jar -cvf hello.jar <最上層包名>
程序的編譯與鏈接
從Java 源代碼到運行的程序,有編譯和鏈接兩個步驟。編譯是將源代碼文件變成擴展名是.class的一種字節(jié)碼,這個工作一般是由 javac 命令完成的。鏈接是在運行時動態(tài)執(zhí)行的,.class 文件不能直接運行,運行的是Java虛擬機,虛擬機聽起來比較抽象,執(zhí)行的就是 Java 命令,這個命令解析 .class文件,轉(zhuǎn)換為機器能識別的二進制代碼,然后運行。所謂鏈接就是根據(jù)引用到的類加載相應的字節(jié)碼并執(zhí)行。
Java編譯和運行時,都需要以參數(shù)指定一個classpath,即類路徑。類路徑可以有多個,對于直接的class文件,路徑是class文件的根目錄;對于jar包,路徑是jar包的完整名稱(包括路徑和jar包名)。
總結(jié)來說,import 是編譯時概念,用于確定完全限定名,在運行時,只根據(jù)完全限定名尋找并加載類,編譯和運行時都依賴類路徑,類路徑中的 jar 文件會被解壓縮用于尋找和加載類。
對象銷毀
對象不再使用時應該銷毀。C++ 語言對象是通過 delete 語句手動釋放,Java語言對象是由垃圾回收器(Garbage Collection)收集然后釋放,程序員不用關(guān)心釋放的細節(jié)。自動內(nèi)存管理是現(xiàn)代計算機語言發(fā)展趨勢,例如:C# 語言的垃圾回收,Objective-C 和 Swift 語言的 ARC(內(nèi)存自動引用計數(shù)管理)。
垃圾回收器(Garbage Collection)的工作原理是:當一個對象的引用不存在時,認為該對象不再需要,垃圾回收器自動掃描對象的動態(tài)內(nèi)存區(qū),把沒有引用的對象作為垃圾收集起來并釋放。