摘要:對(duì)象的引用關(guān)鍵字總是指向調(diào)用該方法的對(duì)象。根據(jù)出現(xiàn)位置的不同,作為對(duì)象的默認(rèn)引用有兩種情形。構(gòu)造器中引用該構(gòu)造器正在初始化的對(duì)象。如果同一個(gè)類中包含了兩個(gè)或兩個(gè)以上方法的方法名相同,但形參列表不同,則被稱為方法重載。
類和對(duì)象 定義類
面向?qū)ο蟮某绦蛟O(shè)計(jì)過(guò)程中有兩個(gè)重要概念:類(class)和對(duì)象(object,也被稱為實(shí)例,instance),其中類是某一批對(duì)象的抽象,可以把類理解成某種概念;對(duì)象才是一個(gè)具體存在的實(shí)體。
[修飾符] class 類名 { 零個(gè)到多個(gè)構(gòu)造器定義... 零個(gè)到多個(gè)成員變量... 零個(gè)到多個(gè)方法... }
修飾符可以是public、final、abstract或者完全忽略。
如果從程序的可讀性方面來(lái)看,Java類名必須由一個(gè)或多個(gè)有意義的單詞連綴而成的,每個(gè)單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
構(gòu)造器是一個(gè)類創(chuàng)建對(duì)象的根本途徑,如果一個(gè)類沒有構(gòu)造器,這個(gè)類通常無(wú)法創(chuàng)建實(shí)例。如果程序員沒有為一個(gè)類編寫構(gòu)造器,則系統(tǒng)會(huì)為該類提供一個(gè)默認(rèn)的構(gòu)造器。一旦程序員為一個(gè)類提供了構(gòu)造器,系統(tǒng)將不再為該類提供構(gòu)造器。
定義成員變量static修飾的成員不能訪問(wèn)沒有static修飾的成員。
成員變量用于定義該類或該類的實(shí)例所包含的狀態(tài)數(shù)據(jù),方法則用于定義該類或該類的實(shí)例的行為特征或者功能實(shí)現(xiàn)。構(gòu)造器用于構(gòu)造該類的實(shí)例,Java語(yǔ)言通過(guò)new關(guān)鍵字來(lái)調(diào)用構(gòu)造器,從而返回該類的實(shí)例。
[修飾符] 類型 成員變量名 [=默認(rèn)值]
修飾符:public、protected、private三個(gè)最多只能出現(xiàn)其中之一,可以與static、final組合起來(lái)修飾成員變量。
類型:基本類型和引用類型
成員變量名:如果從程序的可讀性方面來(lái)看,Java類名必須由一個(gè)或多個(gè)有意義的單詞連綴而成的,第一個(gè)單詞首字母小寫,后面每個(gè)單詞首字母大寫,其他字母全部小寫,單詞與單詞之間不要使用任何分隔符。
默認(rèn)值:定義成員變量還可以指定一個(gè)可選的默認(rèn)值。
定義方法[修飾符] 方法返回值類型 方法名(形參列表) { //由零條到多條可執(zhí)行性語(yǔ)句組成的方法體 }
修飾符:public、protected、private三個(gè)最多只能出現(xiàn)其中之一,可以與static、final組合起來(lái)修飾成員變量。
方法返回值類型:基本類型和引用類型如果聲明了方法返回值類型,則方法體內(nèi)必須與此處聲明的類型匹配。如果一個(gè)方法沒有返回值,則必須使用void來(lái)聲明沒有返回值。
形參列表:形參列表用于定義該方法可以接受的參數(shù),形參列表由零組到多組“參數(shù)類型 形參名”組合而成,多組參數(shù)之間以英文逗號(hào)(,)隔開,形參類型和形參名之間以英文空格隔開。
staticstatic是一個(gè)特殊的關(guān)鍵字,可用于修飾方法、成員變量等成員。static修飾的成員表明它屬于這個(gè)類本身,而不屬于該類的單個(gè)實(shí)例,因?yàn)橥ǔ0裺tatic修飾的成員變量和方法也稱為類變量、類方法。不使用static修飾的普通方法、成員變量則屬于該類的單個(gè)實(shí)例,而不屬于該類。因?yàn)橥ǔ0巡皇褂胹tatic修飾的成員變量和方法也稱為實(shí)例變量、實(shí)例方法。
static修飾的成員變量和方法稱為靜態(tài)變量和靜態(tài)方法,把不使用static修飾的成員變量和方法稱為非靜態(tài)變量和非靜態(tài)方法。靜態(tài)方法不能直接訪問(wèn)非靜態(tài)成員。
有static修飾的成員屬于類本身,沒有static修飾的成員屬于該類的實(shí)例。
構(gòu)造器構(gòu)造器是一個(gè)特殊的方法,定義構(gòu)造器的語(yǔ)法格式與定義方法的語(yǔ)法格式很像,定義構(gòu)造器的語(yǔ)法格式如下:
[修飾符] 構(gòu)造器名(形參列表) { //由零條到多條可執(zhí)行性語(yǔ)句組成的構(gòu)造器執(zhí)行體 }
修飾符:public、protected、private
構(gòu)造器名:構(gòu)造器名必須和類同名
形參列表:和定義方法形參列表的格式完全相同。
構(gòu)造器既不能定義返回值類型,也不能使用void聲明構(gòu)造器沒有返回值。
static修飾的方法和成員變量,既可通過(guò)類來(lái)調(diào)用,也可通過(guò)實(shí)例來(lái)調(diào)用;沒有使用static修飾的普通方法和成員變量,只可通過(guò)實(shí)例來(lái)調(diào)用。
對(duì)象、引用和指針變量實(shí)例實(shí)際上是一個(gè)引用,它被存放在棧內(nèi)存里,指向?qū)嶋H的類對(duì)象;而真正的類對(duì)象則存放在堆內(nèi)存中。棧內(nèi)存里的引用變量并未真正存儲(chǔ)對(duì)象的成員變量,對(duì)象的成員變量數(shù)據(jù)實(shí)際存放在堆內(nèi)存里;而引用變量只是指向該堆內(nèi)存里的對(duì)象。
對(duì)象的this引用this關(guān)鍵字總是指向調(diào)用該方法的對(duì)象。根據(jù)this出現(xiàn)位置的不同,this作為對(duì)象的默認(rèn)引用有兩種情形。
構(gòu)造器中引用該構(gòu)造器正在初始化的對(duì)象。
在方法中引用調(diào)用該方法的對(duì)象。
對(duì)于static修飾的方法而言,則可以使用類來(lái)直接調(diào)用該方法,如果在static修飾的方法中使用this關(guān)鍵字,則這個(gè)關(guān)鍵字就無(wú)法指向合適的對(duì)象。所以,static修飾的方法中不能使用this引用。由于static修飾的方法不能使用this引用,所以static修飾的方法不能訪問(wèn)不使用static修飾的普通成員,因此Java語(yǔ)法規(guī)定:靜態(tài)成員不能直接訪問(wèn)非靜態(tài)成員。
普通方法訪問(wèn)其他方法、成員變量時(shí)無(wú)須使用this前綴,但如果方法里有個(gè)局部變量和成員變量同名,但程序又需要在該方法里訪問(wèn)這個(gè)被覆蓋的成員變量,則必須使用this前綴。this引用也可以用于構(gòu)造器中作為默認(rèn)引用,由于構(gòu)造器是直接使用new關(guān)鍵字來(lái)調(diào)用,而不是使用對(duì)象來(lái)調(diào)用的,所以this在構(gòu)造器中代表該構(gòu)造器正在初始化的對(duì)象。
方法詳解 方法的所屬性Java語(yǔ)言里方法的所屬性主要體現(xiàn)在如下幾個(gè)方面:
方法不能獨(dú)立完成,方法只能在類體里定義。
從邏輯意義上來(lái)看,方法要么屬于該類本身,要么屬于該類的一個(gè)對(duì)象。
永遠(yuǎn)不能獨(dú)立執(zhí)行方法,執(zhí)行方法必須使用類或?qū)ο笞鳛檎{(diào)用者。
同一個(gè)類的一個(gè)方法調(diào)用另一個(gè)方法時(shí),如果被調(diào)用方法是普通方法,則默認(rèn)使用this作為調(diào)用者;如果被調(diào)方法是靜態(tài)方法,則默認(rèn)方法類作為調(diào)用者。
方法的參數(shù)傳遞機(jī)制聲明方法時(shí)包含了形參聲明,則調(diào)用方法時(shí)必須給這些形參指定參數(shù)值,調(diào)用方法時(shí)實(shí)際傳給形參的參數(shù)值也被稱為實(shí)參。
形參個(gè)數(shù)可變的方法Java允許定義形參個(gè)數(shù)可變的參數(shù),從而允許為方法指定數(shù)量不確定的形參。如果在定義方法時(shí),在最后一個(gè)形參的類型后增加三點(diǎn)(...),則表明該形參可以接受多個(gè)參數(shù)值,多個(gè)參數(shù)值被當(dāng)成數(shù)組傳入。
public statci void test(int a, String ... books)
數(shù)組形式的形參可以處于形參列表的任意位置,但個(gè)數(shù)可變的形參只能處于形參列表的最后。也就是說(shuō)一個(gè)方法中最多只能有一個(gè)長(zhǎng)度可變的形參。
遞歸方法一個(gè)方法體內(nèi)調(diào)用它自身,被稱為方法遞歸。方法遞歸包含了一種隱式的循環(huán),它會(huì)重復(fù)執(zhí)行某段代碼,但這種重復(fù)執(zhí)行無(wú)限循環(huán)控制。
希望遍歷某個(gè)路徑下的所有文件,但這個(gè)路徑下文件夾的深度是未知的,那么就可以使用遞歸來(lái)實(shí)現(xiàn)這個(gè)需求。系統(tǒng)可定義一個(gè)方法,該方法接受一個(gè)文件路徑作為參數(shù),該方法可遍歷當(dāng)前路徑下的所有文件和文件路徑——該方法中再次調(diào)用該方法本身來(lái)處理該路徑下的所有文件路徑。
方法重載Java允許同一個(gè)類里定義多個(gè)同名方法,只有形參列表不同就行。如果同一個(gè)類中包含了兩個(gè)或兩個(gè)以上方法的方法名相同,但形參列表不同,則被稱為方法重載。
方法重載三個(gè)因素:
調(diào)用者,也就是方法的所屬者,既可以是類,也可以是對(duì)象。
方法名,方法的標(biāo)識(shí)。
形參列表,當(dāng)調(diào)用方法時(shí),系統(tǒng)將會(huì)根據(jù)傳入的實(shí)參列表匹配。
兩同一不同:同一個(gè)類中方法名相同,參數(shù)列表不同。方法返回值類型、修飾符等,與方法重載沒有任何關(guān)系。
成員變量和局部變量 成員變量成員變量指的是類里定義的變量,也就是前面所介紹的field;局部變量指的是方法里定義的變量。
成員變量:一個(gè)類不能定義兩個(gè)同名的成員變量。
static修飾的類變量。類變量從該類的準(zhǔn)備階段起開始存在,直到系統(tǒng)完全銷毀這個(gè)類,類變量的作用域與這個(gè)類的生存范圍相同;而實(shí)例變量則從該類的實(shí)例被創(chuàng)建起開始存在,直到系統(tǒng)完全銷毀這個(gè)實(shí)例,實(shí)例變量的作用域與對(duì)應(yīng)實(shí)例的生存范圍相同。
成員變量無(wú)須顯式初始化,只要為一個(gè)類定義了類變量或?qū)嵗兞?,系統(tǒng)就會(huì)在這個(gè)類的準(zhǔn)備階段或創(chuàng)建該類的實(shí)例時(shí)進(jìn)行默認(rèn)初始化,成員變量默認(rèn)初始化時(shí)的賦值規(guī)則與數(shù)組動(dòng)態(tài)初始化時(shí)數(shù)組元素的賦值規(guī)則完全相同。
局部變量:一個(gè)方法里不能定義兩個(gè)同名的方法局部變量,方法局部變量與形參也不能同名;同一個(gè)方法中不同代碼塊內(nèi)的代碼塊局部變量可以同名;如果先定義代碼塊局部變量,后定義方法局部變量,前面定義的代碼塊局部變量與后面定義的方法局部變量也可以同名。
形參(方法簽名中定義的變量) 作用域在整個(gè)方法內(nèi)有效 必須顯式初始化
方法局部變量(在方法內(nèi)定義) 作用域從定義該變量的地方生效,到該方法結(jié)束時(shí)失效 必須顯式初始化
代碼塊局部變量(在代碼塊內(nèi)定義) 作用域從定義該變量的地方生效,到該代碼塊結(jié)束時(shí)失效 無(wú)須顯式初始化
Java允許局部變量和成員變量同名,如果方法里的局部變量和成員變量同名,局部變量會(huì)覆蓋成員變量,如果需要在這個(gè)方法里引用被覆蓋的成員變量,則可使用this(對(duì)于實(shí)例變量)或類名(對(duì)于類變量)作為調(diào)用者來(lái)限定訪問(wèn)成員變量。
成員變量的初始化和內(nèi)存中的運(yùn)行機(jī)制當(dāng)系統(tǒng)加載類或創(chuàng)建該類的實(shí)例時(shí),系統(tǒng)自動(dòng)為成員變量分配內(nèi)存空間,并在分配內(nèi)存空間后,自動(dòng)為成員變量指定初始值。
局部變量的初始化和內(nèi)存中的運(yùn)行機(jī)制局部變量定義后,必須經(jīng)過(guò)顯式初始化后才能使用,系統(tǒng)不會(huì)為局部變量執(zhí)行初始化。這意味著定義局部變量后,系統(tǒng)并未為這個(gè)變量分配內(nèi)存空間,直到等到程序?yàn)檫@個(gè)變量賦初始值時(shí),系統(tǒng)才會(huì)為局部變量分配內(nèi)存,并將初始值保存到這塊內(nèi)存中。
變量的使用規(guī)則定義一個(gè)成員變量時(shí),成員變量將被放置到堆內(nèi)存中,成員變量的作用域?qū)U(kuò)大到類存在范圍或者對(duì)象存在范圍,這種范圍的擴(kuò)大有兩個(gè)害處。
增大了變量的生存時(shí)間,這將導(dǎo)致更大的內(nèi)存開銷。
擴(kuò)大了變量的作用域,這不利于提供程序的內(nèi)聚性。
應(yīng)該考慮使用成員變量的情況:
如果需要定義的變量是用于描述某個(gè)類或某個(gè)對(duì)象的固有信息。
如果在某個(gè)類中需要以一個(gè)變量來(lái)保存該類或者實(shí)例運(yùn)行時(shí)的狀態(tài)信息。
如果某個(gè)信息需要在某個(gè)類的多個(gè)方法之間進(jìn)行共享,則這個(gè)信息應(yīng)該使用成員變量來(lái)保存。
即使在程序中使用局部變量,也應(yīng)該盡可能地縮小局部變量的作用范圍,局部變量的作用范圍越小,它在內(nèi)存里停留的時(shí)間就越短,程序運(yùn)行性能就越好。因此,能用代碼塊局部變量的地方,就堅(jiān)決不要使用方法局部變量。
隱藏和封裝 理解封裝封裝指的是將對(duì)象的狀態(tài)信息隱藏在對(duì)象內(nèi)部,不允許外部程序直接訪問(wèn)對(duì)象內(nèi)部信息,二世通過(guò)該類所提供的方法來(lái)實(shí)現(xiàn)對(duì)內(nèi)部信息的操作和訪問(wèn)。
對(duì)一個(gè)類或?qū)ο髮?shí)現(xiàn)良好的封裝,可以實(shí)現(xiàn)以下目的。
隱藏類的實(shí)現(xiàn)細(xì)節(jié)
讓使用者只能通過(guò)事先預(yù)定的方法來(lái)訪問(wèn)數(shù)據(jù),從而可以在該方法里加入控制邏輯,限制對(duì)成員變量的不合理訪問(wèn)。
可進(jìn)行數(shù)據(jù)檢查,從而有利于保證對(duì)象信息的完整性。
便于修改,提高代碼的可維護(hù)性。
為了實(shí)現(xiàn)良好的封裝,需要從兩個(gè)方面考慮:
將對(duì)象的成員變量和實(shí)現(xiàn)細(xì)節(jié)隱藏起來(lái),不允許外部直接訪問(wèn)。
把方法暴露出來(lái),讓方法來(lái)控制對(duì)這些成員變量進(jìn)行安全的訪問(wèn)和操作。
使用訪問(wèn)控制符private → default → protected → public
訪問(wèn)控制級(jí)別由小到大
private(當(dāng)前類訪問(wèn)權(quán)限):使用它來(lái)修飾成員變量就可以把成員變量隱藏在該類的內(nèi)部。
default(包訪問(wèn)權(quán)限):defaulte訪問(wèn)控制的成員或外部類可以被相同包下的其他類訪問(wèn)。
protected(子類訪問(wèn)權(quán)限):成員既可以被同一包中的其他類訪問(wèn),也可以被不同包中的子類訪問(wèn)。通常,如果使用protected來(lái)修飾一個(gè)方法,是希望其子類來(lái)重寫這個(gè)方法。
public(公共訪問(wèn)權(quán)限):成員或外部類可以被所以類訪問(wèn),不管訪問(wèn)類和被訪問(wèn)類是否處于同一包中,是否具有父子繼承關(guān)系。
private default protected public 同一個(gè)類中 √ √ √ √ 同一個(gè)包中 √ √ √ 子類中 √ √ 全局范圍內(nèi) √
外部類只能有兩種訪問(wèn)控制級(jí)別:public和default,外部類不能用private和protected修飾,因?yàn)橥獠款悰]有處于任何類內(nèi)部,也就沒有其所在類的內(nèi)部、所在類的子類的兩個(gè)范圍。
如果一個(gè)Java類的每個(gè)實(shí)例變量都被使用private修飾,并為每個(gè)實(shí)例變量都提供了public修飾setter和getter方法,那么這個(gè)類就是一個(gè)符號(hào)JavaBean規(guī)范的類。因此,JavaBean總是一個(gè)封裝良好的類。
進(jìn)行程序設(shè)計(jì)時(shí),應(yīng)盡量避免一個(gè)模塊直接操作和訪問(wèn)另一個(gè)模塊的數(shù)據(jù),模塊設(shè)計(jì)追求高內(nèi)聚(盡可能把模塊的內(nèi)部數(shù)據(jù)、功能實(shí)現(xiàn)細(xì)節(jié)隱藏在模塊內(nèi)部獨(dú)立完成,不允許外部直接干預(yù))、低耦合(僅暴露少量的方法給外部使用)。
訪問(wèn)控制符的使用的基本原則:
類里的絕大部分成員變量都應(yīng)該使用private,只有一些static修飾的、類似全局變量的成員變量,才可能考慮使用public修飾。除此之外,有些方法只用于輔助實(shí)現(xiàn)該類的其他方法,這些方法被稱為工具方法,工具方法也應(yīng)該使用private修飾。
如果某個(gè)類主要用作其他類的父類,該類里包含的大部分方法可能僅希望被其子類重寫,而不想被外界直接調(diào)用,則應(yīng)該使用protected修飾這些方法。
希望暴露出來(lái)給其他類自由調(diào)用的方法應(yīng)該使用public修飾。因此,類的構(gòu)造器通過(guò)public修飾,從而允許在其他地方創(chuàng)建該類的實(shí)例。因?yàn)橥獠款愅ǔ6枷M黄渌愖杂墒褂茫源蟛糠滞獠款惗际褂胮ublic修飾。
package、import和import static如果希望把一個(gè)類放到指定的包結(jié)構(gòu)下,應(yīng)該在Java源程序的第一個(gè)非注釋行放置如下格式的代碼:
package packageName;
一旦在Java源文件中使用了這個(gè)package語(yǔ)句,就意味著該源文件里定義的所有類都屬于這個(gè)包。位于包中的每個(gè)類的完整類名都應(yīng)該是包名和類名的組合,如果其他人需要使用該包下的類,也應(yīng)該使用包名加類名的組合。
同一個(gè)包中的類不必位于相同的目錄下,例如有l(wèi)eePerson和LeePersonTest兩個(gè)類,它們完全可以一個(gè)位于C盤下某個(gè)位置,一個(gè)位于D盤下某個(gè)位置,只要讓CLASSPATH環(huán)境變量里包含這兩個(gè)路徑即可。虛擬機(jī)會(huì)自動(dòng)搜索CLASSPATH下的子路徑,把它們當(dāng)成同一個(gè)包下的類來(lái)處理。也應(yīng)該把Java源文件放在與包名一致的目錄結(jié)構(gòu)下。通常建議將源文件和class文件分開存放,以便管理。
從可讀性規(guī)范角度來(lái)看,包名應(yīng)該全部是小寫字母,而且應(yīng)該由一個(gè)或多個(gè)有意義的單詞連綴而成。
package語(yǔ)句必須作為源文件的第一條非注釋性語(yǔ)句,一個(gè)源文件只能指定一個(gè)包,即只能包含一條package語(yǔ)句,該源文件中可以定義多個(gè)類,則這些類將全部位于該包下。如果沒有顯式指定package語(yǔ)言,則處于默認(rèn)包下。
同一個(gè)包下的類可以自由訪問(wèn),無(wú)須添加包前綴。
父包和子包之間確實(shí)表示了某種內(nèi)在的邏輯關(guān)系。但父包和子包在用法上不存在任何關(guān)系,如果父包中的類需要使用子包中的類,則必須使用子包的全名,而不能省略父包部分。
//調(diào)用構(gòu)造器時(shí)需要在構(gòu)造器前添加包前綴 lee.sub.Apple a = new lee.sub.Apple();import關(guān)鍵字
import可以向某個(gè)Java文件中導(dǎo)入指定包層次下某個(gè)類或全部類,import語(yǔ)句應(yīng)該出現(xiàn)在package語(yǔ)句之后(如果有)、類定義之前。一個(gè)Java源文件只能包含一個(gè)package語(yǔ)句,但可以包含多個(gè)import語(yǔ)句,多個(gè)import語(yǔ)句用于導(dǎo)入多個(gè)包層次下的類。java.lang包下的所有類默認(rèn)導(dǎo)入。
//使用import語(yǔ)句導(dǎo)入單個(gè)類 import package.subpackage...ClassName; //使用import語(yǔ)句導(dǎo)入指定包下全部 import package.subpackage.*
星號(hào)()只能代表類,不能代表包。因此使用import.lee.;語(yǔ)句時(shí),它表明導(dǎo)入lee包下的所有類,而lee包下sub子包內(nèi)的類則不會(huì)被導(dǎo)入。如需導(dǎo)入lee.sub.Apple類,則可以使用impor.lee.sub.*;語(yǔ)句來(lái)導(dǎo)入lee.sub包下的所有類。
一旦在Java源文件中使用import語(yǔ)句來(lái)導(dǎo)入指定類,在該源文件中使用這些類時(shí)就可以省略包前綴,不再需要使用類全名。
靜態(tài)導(dǎo)入import static
import static package.subpackage..ClassName.fieldName|methodName; field:靜態(tài)成員變量;methodName:靜態(tài)方法。 使用import可以省略寫包名;使用import static則可以連類名都省略。
Java源文件的大致結(jié)構(gòu):
package語(yǔ)句 //0個(gè)或1個(gè),必須放在文件開始 import | import static 語(yǔ)句 //0個(gè)或多個(gè),必須放在所有類定義之前 public classDefinition | interfaceDefinition | enumDefinition //0個(gè)或1個(gè)public類、接口或枚舉定義 classDefinition | interfaceDefinition | enumDefinition //0個(gè)或多個(gè)普通類、接口或枚舉定義Java的常用包
Java.lang:核心類,如String、Math、System和thread類等,使用這個(gè)包下的類無(wú)須使用import語(yǔ)句導(dǎo)入,系統(tǒng)會(huì)自動(dòng)導(dǎo)入這個(gè)包下的所有類。 java.util:Java的大量工具類/接口和集合框架類/接口,例如Arrays和List、Set等 java.net:一些Java網(wǎng)絡(luò)編程相關(guān)的類/接口 java.io:一些Java輸入/輸出編程相關(guān)的類/接口 java.text:一些Java格式化相關(guān)的類 java.sql:Java進(jìn)行JDBC數(shù)據(jù)庫(kù)編程的想相關(guān)類/接口 java.awt:抽象窗口工具集的相關(guān)類/接口,這些類主要用于構(gòu)建圖形用戶界面GUI程序 java.swing:Swing圖形用戶界面編程的相關(guān)類/接口,這些類可用于構(gòu)建平臺(tái)無(wú)關(guān)的GUI程序深入構(gòu)造器
構(gòu)造器是一個(gè)特殊的方法,用于創(chuàng)建實(shí)例時(shí)執(zhí)行初始化。
使用構(gòu)造器執(zhí)行當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),系統(tǒng)為這個(gè)對(duì)象的實(shí)例變量進(jìn)行默認(rèn)初始化,這種默認(rèn)的初始化把所有基本類型的實(shí)例變量設(shè)為0或false,把所有引用類型的實(shí)例變量設(shè)為Null。
如果程序員沒有為Java類提供任何構(gòu)造器,則系統(tǒng)會(huì)為這個(gè)類提供一個(gè)無(wú)參數(shù)的構(gòu)造器,這個(gè)構(gòu)造器的執(zhí)行體為空,不做任何事情。無(wú)論如何,Java類至少包含一個(gè)構(gòu)造器。
通常把構(gòu)造器設(shè)置為public訪問(wèn)權(quán)限,從而允許系統(tǒng)中任何位置的類來(lái)創(chuàng)建該類的對(duì)象。
構(gòu)造器重載同一個(gè)類里具有多個(gè)構(gòu)造器,多個(gè)構(gòu)造器的形參列表不同,即被稱為構(gòu)造器重載,構(gòu)造器重載允許Java類里包含多個(gè)初始化邏輯,從而允許使用不同的構(gòu)造器來(lái)初始化Java對(duì)象。
類的繼承 繼承的特點(diǎn)Java的繼承通過(guò)extends關(guān)鍵字來(lái)實(shí)現(xiàn),實(shí)現(xiàn)繼承的類被稱為子類,被繼承的類被稱為父類。父類與子類的關(guān)系,是一種一般和特殊的關(guān)系。Java類只能有一個(gè)直接父類。
修飾符 class SubClass extends SuperClass { //類定義部分 }
java.lang.Object類是所有類的父類,要么是直接父類,要么是其間接父類。因此所有的java對(duì)象都可以調(diào)用java.lang.Object類定義的實(shí)例方法。
重寫父類的方法子類包含與父類同名方法你的現(xiàn)象被稱為方法重寫(Override),也稱為方法覆蓋。
方法的重寫遵循“兩同兩小一大”規(guī)則
“兩同”:方法名、形參列表相同;
“兩小”:子類方法返回值類型應(yīng)比父類返回值類型更小或相等,子類方法聲明拋出的異常類應(yīng)比父類方法聲明拋出的異常類更小或相等。
“一大”:子類方法的訪問(wèn)權(quán)限應(yīng)比父類方法的訪問(wèn)權(quán)限更大或相等。
覆蓋方法和被覆蓋方法要么都是類方法,要么都是實(shí)例方法,不能一個(gè)類方法,一個(gè)是實(shí)例方法。
當(dāng)子類覆蓋了父類方法后,子類的對(duì)象將無(wú)法訪問(wèn)父類中被覆蓋的方法,但可以在子類方法中調(diào)用父類中被覆蓋的方法。如果需要在子類方法最后調(diào)用父類中被覆蓋的方法,則可以使用super(被覆蓋的是實(shí)例方法)或者父類類名(被覆蓋的是類方法)作為調(diào)用者來(lái)調(diào)用父類中被覆蓋的方法。
如果父類方法具有private訪問(wèn)權(quán)限,則該方法對(duì)其子類是隱藏的,因此其子類無(wú)法訪問(wèn)該方法,也就是無(wú)法重寫該方法。如果子類中定義了一個(gè)與父類private方法具有相同的方法名、相同的形參列表、相同的返回值類型的方法,依然不是重寫,只是在子類中重新定義了一個(gè)新方法。
super限定如果需要在子類方法中調(diào)用父類被覆蓋的實(shí)例方法,則可使用super限定來(lái)調(diào)用父類被覆蓋的實(shí)例方法。super用于限定該對(duì)象調(diào)用它從父類繼承得到的實(shí)例變量或方法。this和super均不能出現(xiàn)在static修飾的方法中。
如果在某個(gè)方法中訪問(wèn)名為a的成員變量,但沒有顯式指定調(diào)用者,則系統(tǒng)查找a的順序?yàn)椋?/p>
查找該方法中是否有名為a的局部變量。
查找當(dāng)前類中是否包括名為a的成員變量。
查找a的直接父類中是否包含名為a的成員變量,依次上溯a的所有父類,直到j(luò)ava.lang.Object類,如果最終不能找到名為a的成員變量,則系統(tǒng)出現(xiàn)編譯錯(cuò)誤。
如果被覆蓋的是類變量,在子類的方法中則可以通過(guò)父類名作為調(diào)用者來(lái)訪問(wèn)被覆蓋的類變量。
當(dāng)程序創(chuàng)建一個(gè)子類對(duì)象時(shí),系統(tǒng)不僅會(huì)為該類中定義的實(shí)例變量分配內(nèi)存,也會(huì)為它從父類繼承得到的所有實(shí)例變量分配內(nèi)存,即使子類定義了與父類中同名的實(shí)例變量。
調(diào)用父類構(gòu)造器在一個(gè)構(gòu)造器中調(diào)用另一個(gè)重載的構(gòu)造器使用this來(lái)完成,在子類構(gòu)造器使用super調(diào)用來(lái)完成。this和super調(diào)用構(gòu)造器必須出現(xiàn)在構(gòu)造器執(zhí)行體的第一行。
子類構(gòu)造器調(diào)用父類構(gòu)造器分如下幾種情況:
子類構(gòu)造器執(zhí)行體的第一行使用super顯式調(diào)用父類構(gòu)造器,系統(tǒng)將根據(jù)super調(diào)用里傳入的實(shí)參列表調(diào)用父類對(duì)應(yīng)的構(gòu)造器。
子類構(gòu)造器執(zhí)行體的第一行代碼使用this顯式調(diào)用本類中重載構(gòu)造器,系統(tǒng)將根據(jù)this調(diào)用里傳入的實(shí)參列表調(diào)用本類中的另一個(gè)構(gòu)造器。執(zhí)行本類中另一個(gè)構(gòu)造器時(shí)即會(huì)調(diào)用父類構(gòu)造器。
子類構(gòu)造器執(zhí)行體中既沒有super調(diào)用,也沒有this調(diào)用,系統(tǒng)將會(huì)在執(zhí)行子類構(gòu)造器之前,隱式調(diào)用父類無(wú)參數(shù)的構(gòu)造器。
創(chuàng)建任何java對(duì)象,最先執(zhí)行的總是java.lang.Object類的構(gòu)造器。即,創(chuàng)建任何對(duì)象總是從該類所在繼承樹最頂層類的構(gòu)造器開始執(zhí)行,然后依次向下執(zhí)行,最后才執(zhí)行本類的構(gòu)造器。如果某個(gè)父類通過(guò)this調(diào)用了同類中重載的構(gòu)造器,就會(huì)依次執(zhí)行此父類的多個(gè)構(gòu)造器。
多態(tài) 多態(tài)性Java引用變量有兩個(gè)類型:編譯時(shí)類型,運(yùn)行時(shí)類型。
編譯時(shí)類型由聲明該變量時(shí)使用的類型決定,運(yùn)行時(shí)類型由實(shí)際賦給該變量的對(duì)象決定。如果編譯時(shí)類型和運(yùn)行時(shí)類型不一致,就可能出現(xiàn)所謂的多態(tài)。
BaseClass bc = new BaseClass(); SubClass sc = new SubClass(); BaseClass polymorphicBc = new SubClass();
上面程序顯式創(chuàng)建了三個(gè)引用變量,對(duì)于前兩個(gè)引用變量bc和sc,它們編譯時(shí)類型和運(yùn)行時(shí)類型完全相同,因此調(diào)用它們的成員變量和方法非常正常,完全沒有任何問(wèn)題。但第三個(gè)引用變量polymorphic則比較特殊,它的編譯時(shí)類型是BaseClass,而運(yùn)行時(shí)類型是SubClass,當(dāng)調(diào)用該引用變量的test()方法(BaseClass類中定義了該方法,子類SubClass覆蓋了父類的該方法)時(shí),實(shí)際執(zhí)行的是SubClass類中覆蓋后的test()方法,這就可能出現(xiàn)多態(tài)了。
因?yàn)樽宇惼鋵?shí)是一種特殊的父類,因此Java允許把一個(gè)子類對(duì)象直接賦給一個(gè)父類引用變量,無(wú)須任何類型轉(zhuǎn)換,或者被稱為向上轉(zhuǎn)型(upcasting),向上轉(zhuǎn)型由系統(tǒng)自動(dòng)完成。
相同類型的變量、調(diào)用同一方法時(shí)呈現(xiàn)出多種不同的行為特征,這就是多態(tài)。
polymorphicBc.sub();這行代碼會(huì)在編譯時(shí)引發(fā)錯(cuò)誤。雖然polymorphicBc引用變量實(shí)際上確實(shí)包含sub()方法,但因?yàn)樗木幾g時(shí)類型為BaseClass,因此編譯時(shí)無(wú)法調(diào)用sub方法。
與方法不同的是,對(duì)象的實(shí)例變量則不具備多態(tài)性。比如上面的polymorphicBc引用變量,程序中輸出它的book實(shí)例變量時(shí),并不是輸出SubClass類里定義的實(shí)例變量,而是輸出BaseClass類的實(shí)例變量。
引用變量在編譯階段只能調(diào)用其編譯時(shí)類型所具有的方法,但運(yùn)行時(shí)則執(zhí)行它運(yùn)行時(shí)類型所具有的方法。因此,編寫Java代碼時(shí),引用變量只能調(diào)用聲明該變量時(shí)所用類里包含的方法。例如,通過(guò)Object p = new Person()代碼定義了一個(gè)變量p,則這個(gè)p只能調(diào)用Object類的方法,而不能調(diào)用Person類里定義的方法。
通過(guò)引用變量來(lái)訪問(wèn)其包含的實(shí)例變量時(shí),系統(tǒng)總是試圖訪問(wèn)它編譯時(shí)類型所定義的成員變量,而不是它運(yùn)行時(shí)類型所定義的成員變量。
引用變量的強(qiáng)制類型轉(zhuǎn)換編寫Java程序時(shí),引用變量只能調(diào)用它編譯時(shí)類型的方法,而不能調(diào)用它運(yùn)行時(shí)類型的方法,即使它實(shí)際所引用的對(duì)象卻是包含該方法。如果需要讓這個(gè)引用變量調(diào)用它運(yùn)行時(shí)類型的方法,則必須把它強(qiáng)制類型轉(zhuǎn)換成運(yùn)行時(shí)類型,強(qiáng)制類型轉(zhuǎn)換需要借助于類型轉(zhuǎn)換運(yùn)算符。
當(dāng)進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí)需要注意:
基本類型之間的轉(zhuǎn)換只能在數(shù)值類型之間進(jìn)行,這里所說(shuō)的數(shù)組類型包括整數(shù)性、字符型和浮點(diǎn)型。但數(shù)值型和布爾類型直接不能進(jìn)行類型轉(zhuǎn)換。
引用類型直接的轉(zhuǎn)換只能在具有繼承關(guān)系的兩個(gè)類型之間進(jìn)行,如果是兩個(gè)沒有任何繼承關(guān)系的類型,則無(wú)法進(jìn)行類型轉(zhuǎn)換,否則編譯時(shí)就會(huì)出現(xiàn)錯(cuò)誤。如果試圖把一個(gè)父類實(shí)例轉(zhuǎn)換成子類實(shí)例,則這個(gè)對(duì)象必須實(shí)際上是子類實(shí)例才行(即編譯時(shí)類型為福類型,而運(yùn)行時(shí)類型是子類類型),否則將在運(yùn)行時(shí)引發(fā)ClassCastException異常。
進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí)可能出現(xiàn)異常,因此進(jìn)行類型轉(zhuǎn)換之前應(yīng)先通過(guò)instanceof運(yùn)算符來(lái)判斷是否可以成功轉(zhuǎn)換,從而避免出現(xiàn)ClassCastException異常,這樣可以保證程序更加健壯。
instanceof運(yùn)算符instanceof運(yùn)算符的前一個(gè)操作數(shù)通常是一個(gè)引用類型變量,后一個(gè)操作數(shù)通常是一個(gè)類(也可以是接口),它用于判斷前面的對(duì)象是否是后面的類,或者其子類、實(shí)現(xiàn)類的實(shí)例。如果是返回true,否則返回false。
instanceof運(yùn)算符前面操作數(shù)的編譯時(shí)類型要么與后面的類相同,要么與后面的類具有父子繼承關(guān)系,否則會(huì)引起編譯錯(cuò)誤。
instanceof和(type)是Java提供的兩個(gè)相關(guān)的運(yùn)算符,通常先用instanceof判斷一個(gè)對(duì)象是否可以強(qiáng)制類型轉(zhuǎn)換,然后再使用(type)運(yùn)算符進(jìn)行強(qiáng)制類型轉(zhuǎn)換,從而保證程序不會(huì)出現(xiàn)錯(cuò)誤。
繼承與組合 使用繼承的注意點(diǎn)為了保證父類有良好的封裝性,不會(huì)被子類隨意改變,設(shè)計(jì)父類通常應(yīng)該遵循如下規(guī)則。
盡量隱藏父類的內(nèi)部結(jié)構(gòu)。盡量把父類的所有變量都設(shè)置成private訪問(wèn)類型,不要讓子類直接訪問(wèn)父類的成員變量。
不要讓子類可以隨意訪問(wèn)、修改父類的方法。父類中那些僅為輔助其他的工具方法,應(yīng)該使用private訪問(wèn)控制符修飾,讓子類無(wú)法訪問(wèn)該方法;如果父類中的方法需要被外部類調(diào)用,則必須以public修飾,但又不希望子類重寫該方法,可以使用final修飾符(該修飾符后面會(huì)有更詳細(xì)的介紹)來(lái)修飾該方法。如果希望父類的某個(gè)方法被子類重寫,但不希望被其他類自由訪問(wèn),則可以使用protected來(lái)修飾該方法。
盡量不要在父類構(gòu)造器中調(diào)用將要被子類重寫的方法。 將引發(fā)空指針異常。
如果想把某些類設(shè)置成最終類,既不能被當(dāng)成父類,則可以使用final修飾這個(gè)類;使用private修飾這個(gè)類的所有構(gòu)造器,從而保證子類無(wú)法調(diào)用該類的構(gòu)造器,也就無(wú)法繼承該類的實(shí)例。
何時(shí)需要從父類派生新的子類:
子類需要額外增加屬性,而不僅僅是屬性值的改變。
子類需要增加自己獨(dú)有的行為方式(包括增加新的方法或重寫父類的方法)。
利用組合實(shí)現(xiàn)復(fù)用對(duì)于繼承而已,子類可以直接獲得父類的public方法,程序使用子類時(shí),將可以直接訪問(wèn)該子類從父類那里繼承到的方法;而組合則是把舊類對(duì)象作為新類的成員變量組合進(jìn)來(lái),用以實(shí)現(xiàn)新類的功能,用戶看到的是新類的方法,而不能看到被組合對(duì)象的方法。
繼承要表達(dá)的是一種“是(is-a)”的關(guān)系,而組合表達(dá)的是“有(has-a)”的關(guān)系。
初始化塊 使用初始化塊初始化塊是Java類里可出現(xiàn)的第4種成員(前面依次有成員變量、方法和構(gòu)造器),一個(gè)類里可以有多個(gè)初始化塊,相同類型的初始化塊之間有順序:前面定義的初始化塊先執(zhí)行,后面定義的初始化塊后執(zhí)行。
[修飾符] { //初始化塊的可執(zhí)行性代碼 }
初始化塊的修飾符只能是static,使用static修飾的初始化塊被稱為靜態(tài)初始化塊。初始化塊里的代碼可以包含任何可執(zhí)行性語(yǔ)句,包括定義局部變量、調(diào)用其他對(duì)象的方法,以及使用分支、循環(huán)語(yǔ)句等。
當(dāng)創(chuàng)建Java對(duì)象時(shí),系統(tǒng)總是先調(diào)用該類里定義的初始化塊,如果一個(gè)類里定義了2個(gè)普通初始化塊,則前面定義的初始化塊先執(zhí)行,后面定義的初始化塊后執(zhí)行。初始化塊只在創(chuàng)建Java對(duì)象時(shí)隱式執(zhí)行,而且在執(zhí)行構(gòu)造器之前執(zhí)行。
初始化塊和構(gòu)造器與構(gòu)造器不同的是,初始化塊是一段固定執(zhí)行的代碼,它不能接收任何參數(shù)。
靜態(tài)初始化塊如果定義初始化塊時(shí)使用了static修飾符,則這個(gè)初始化塊就變成了靜態(tài)初始化塊,也被稱為類初始化塊(普通初始化塊負(fù)責(zé)對(duì)對(duì)象執(zhí)行初始化,類初始化塊則負(fù)責(zé)對(duì)類進(jìn)行初始化)。靜態(tài)初始化塊是類相關(guān)的,系統(tǒng)將在類初始化階段執(zhí)行靜態(tài)初始化塊,而不是在創(chuàng)建對(duì)象時(shí)才執(zhí)行。因此靜態(tài)初始化塊總是比普通初始化塊先執(zhí)行。
靜態(tài)初始化塊也被稱為類初始化塊,也屬于類的靜態(tài)成員,同樣需要遵循靜態(tài)成員不能訪問(wèn)非靜態(tài)成員的規(guī)則,因此靜態(tài)初始化塊不能訪問(wèn)非靜態(tài)成員,包括不能訪問(wèn)實(shí)例變量和實(shí)例方法。
系統(tǒng)在類初始化階段執(zhí)行靜態(tài)初始化塊時(shí),不僅會(huì)執(zhí)行本類的靜態(tài)初始化塊,而且還會(huì)一直上溯到j(luò)ava.lang.Object類(如果它包含靜態(tài)初始化塊),先執(zhí)行java.lang.Object類的靜態(tài)初始化塊(如果有),然后執(zhí)行其父類的靜態(tài)初始化塊······最后才執(zhí)行該類的靜態(tài)初始化塊。
系統(tǒng)在創(chuàng)建一個(gè)Java對(duì)象時(shí),不僅會(huì)執(zhí)行該類的普通初始化塊和構(gòu)造器,而且系統(tǒng)會(huì)一直上溯到j(luò)ava.lang.Object類,先執(zhí)行java.lang.Object類的初始化塊,開始執(zhí)行java.lang.Object的構(gòu)造器,一次向下執(zhí)行其父類的初始化塊,開始執(zhí)行其父類的構(gòu)造器······最后才執(zhí)行該類的初始化塊和構(gòu)造器,返回該類的對(duì)象。
當(dāng)JVM第一次主動(dòng)使用某個(gè)類時(shí),系統(tǒng)會(huì)在類準(zhǔn)備階段為該類的所有靜態(tài)成員變量分配內(nèi)存;在初始化階段則負(fù)責(zé)初始化這些靜態(tài)成員變量,初始化靜態(tài)成員變量就是執(zhí)行類初始化代碼或者聲明類成員變量時(shí)指定的初始值,它們的執(zhí)行順序與源代碼中的排列順序相同。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/66140.html
摘要:對(duì)象既是該類事物實(shí)實(shí)在在存在的個(gè)體。類與對(duì)象的關(guān)系圖類就是汽車汽車就是堆內(nèi)存中的對(duì)象。成員變量成員變量成員函數(shù)的車,輪胎數(shù)個(gè),跑起來(lái)了對(duì)象的創(chuàng)建創(chuàng)建對(duì)象中創(chuàng)建對(duì)象,使用關(guān)鍵字在堆內(nèi)存中開辟了空間,產(chǎn)生了一個(gè)實(shí)體。 聲明:本文首發(fā)于我的個(gè)人微信公眾號(hào)【Java編程社區(qū)】,查看更多文章與學(xué)習(xí)資源請(qǐng)移步我的公眾號(hào)Java編程社區(qū) 萬(wàn)物皆對(duì)象 學(xué)習(xí)Java,我們都聽過(guò)這句話:萬(wàn)物皆對(duì)象。那么什...
摘要:是一種典型的面向?qū)ο缶幊陶Z(yǔ)言。這篇文章主要是來(lái)初步理解一下面向?qū)ο蟮乃季S為下面的內(nèi)容先給一個(gè)基礎(chǔ)。針對(duì)面向?qū)ο缶幊痰母鄡?nèi)容,會(huì)在后面的文章里面詳細(xì)解釋。他們都稱之為對(duì)象。之后,我們?cè)儆镁幊陶Z(yǔ)言,把這種映射編寫出來(lái),就是的面向?qū)ο缶幊汤病? showImg(https://segmentfault.com/img/remote/1460000012983458?w=900&h=500);...
摘要:眾多面向?qū)ο蟮木幊趟枷腚m不盡一致,但是無(wú)論哪種面向?qū)ο缶幊陶Z(yǔ)言都具有以下的共通功能。原型編程以類為中心的傳統(tǒng)面向?qū)ο缶幊蹋且灶悶榛A(chǔ)生成新對(duì)象。而原型模式的面向?qū)ο缶幊陶Z(yǔ)言沒有類這樣一個(gè)概念。 什么是面向?qū)ο螅窟@個(gè)問(wèn)題往往會(huì)問(wèn)到剛畢業(yè)的新手or實(shí)習(xí)生上,也是往往作為一個(gè)技術(shù)面試的開頭題。在這里我們不去談如何答(fu)好(yan)問(wèn)(guo)題(qu),僅談?wù)勎宜斫獾拿嫦驅(qū)ο蟆?從歷...
摘要:面向?qū)ο笈c面向過(guò)程的區(qū)別要知道,二者并不是非此即彼,而是相輔相成的。而面向過(guò)程,則在微觀上對(duì)對(duì)象內(nèi)部進(jìn)行具體的實(shí)現(xiàn)。面向?qū)ο蟮娜筇匦哉f(shuō)到面向?qū)ο螅筒坏貌徽f(shuō)其三大特性封裝繼承和多態(tài)。封裝封裝是面向?qū)ο笞罨A(chǔ)的特性。 作者:伯特出處:github.com/ruicbAndroid/LoulanPlan聲明:本文出自伯特的《LoulanPlan》,轉(zhuǎn)載務(wù)必注明作者及出處。 剛學(xué)習(xí) Jav...
摘要:知識(shí)點(diǎn)總結(jié)面向?qū)ο笾R(shí)點(diǎn)總結(jié)面向?qū)ο竺嫦驅(qū)ο蟾拍钍窍鄬?duì)于面向過(guò)程而言,過(guò)程其實(shí)就是函數(shù),對(duì)象是將函數(shù)和屬性進(jìn)行了封裝。指向了該對(duì)象關(guān)鍵字代表對(duì)象。靜態(tài)變量所屬于類,所以也稱為類變量成員變量存在于堆內(nèi)存中。 Java知識(shí)點(diǎn)總結(jié)(面向?qū)ο螅?@(Java知識(shí)點(diǎn)總結(jié))[Java, Java面向?qū)ο骫 [toc] 面向?qū)ο蟾拍?是相對(duì)于面向過(guò)程而言,過(guò)程其實(shí)就是函數(shù),對(duì)象是將函數(shù)和屬性進(jìn)行了封...
摘要:最近在備戰(zhàn)面試的過(guò)程中,整理一下面試題。成員變量如果沒有被賦初值,則會(huì)自動(dòng)以類型的默認(rèn)值而賦值一種情況例外被修飾但沒有被修飾的成員變量必須顯示地賦值而局部變量則不會(huì)自動(dòng)賦值。 最近在備戰(zhàn)面試的過(guò)程中,整理一下面試題。大多數(shù)題目都是自己手敲的,網(wǎng)上也有很多這樣的總結(jié)。自己感覺總是很亂,所以花了很久把自己覺得重要的東西總結(jié)了一下。 面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別 面向過(guò)程: 優(yōu)點(diǎn):性能比面...
閱讀 3222·2023-04-25 18:43
閱讀 903·2021-11-24 09:39
閱讀 1367·2021-10-14 09:43
閱讀 3902·2021-09-22 15:58
閱讀 1923·2019-08-29 17:18
閱讀 421·2019-08-29 14:14
閱讀 3086·2019-08-29 13:01
閱讀 1623·2019-08-29 12:33