繼承
為什么要有繼承礁鲁?
多個(gè)類中存在相同屬性和行為時(shí)绎晃,將這些內(nèi)容抽取到單獨(dú)一個(gè)類(父類、基類或超類)中椎镣,那么多個(gè)類(子類)無需再定義這些屬性和行為诈火,只要繼承那個(gè)類即可。
繼承的作用:
繼承的出現(xiàn)提高了代碼的復(fù)用性状答。
繼承的出現(xiàn)讓類與類之間產(chǎn)生了關(guān)系冷守,提供了多態(tài)的前提。
不要僅為了獲取其他類中某個(gè)功能而去繼承
子類是對父類的擴(kuò)展
關(guān)于繼承的規(guī)則:
子類不能直接訪問父類中私有的(private)的成員變量和方法惊科。
Java只支持單繼承拍摇,不允許多重繼承方法的重寫-override
定義:在子類中可以根據(jù)需要對從父類中繼承來的方法進(jìn)行改造,也稱方法的重置馆截、覆蓋充活。在程序執(zhí)行時(shí)蜂莉,子類的方法將覆蓋父類的方法。
要求:
重寫方法必須和被重寫方法具有相同的方法名稱混卵、參數(shù)列表和返回值類型映穗。(只能重寫方法體)
重寫方法不能使用比被重寫方法更嚴(yán)格的訪問權(quán)限。
重寫和被重寫的方法須同時(shí)為static的淮菠,或同時(shí)為非static的
子類方法拋出的異常不能大于父類被重寫方法的異常四種訪問權(quán)限修飾符
如果子類和父類在同一個(gè)包下男公,那么對于父類的成員,只要不是私有的合陵,子類都可以使用
如果子類和父類不在同一個(gè)包下枢赔,子類只能使用父類中的public和protected的成員關(guān)鍵字super
在Java類中使用super來調(diào)用父類中的指定操作:
super可用于訪問父類中定義的屬性
super可用于調(diào)用父類中定義的成員方法
super可用于在子類構(gòu)造方法中調(diào)用父類的構(gòu)造器
注意:
尤其當(dāng)子父類出現(xiàn)同名成員時(shí),可以用super進(jìn)行區(qū)分
super的追溯不僅限于直接父類
super和this的用法相像拥知,this代表本類對象的引用踏拜,super代表父類的內(nèi)存空間的標(biāo)識
使用super,子類可以調(diào)用所有層級的父類
調(diào)用父類的構(gòu)造器:
子類中所有的構(gòu)造器默認(rèn)都會(huì)訪問父類中空參數(shù)的構(gòu)造器
當(dāng)父類中沒有空參數(shù)的構(gòu)造器時(shí)低剔,子類的構(gòu)造器必須通過this(參數(shù)列表)或者super(參數(shù)列表)語句指定調(diào)用本類或者父類中相應(yīng)的構(gòu)造器速梗,且必須放在構(gòu)造器的第一行(父類只有有參構(gòu)造函數(shù)可以使用時(shí),子類必須顯示的構(gòu)建一個(gè)構(gòu)造來調(diào)用父類的有參構(gòu)造襟齿,并且調(diào)用父類的方法寫在第一行)
如果子類構(gòu)造器中既未顯式調(diào)用父類或本類的構(gòu)造器姻锁,且父類中又沒有無參的構(gòu)造器,則編譯出錯(cuò)-
this和super的區(qū)別:
注意:在子類中猜欺,通過this和super調(diào)用構(gòu)造器位隶,只能使用一個(gè),因?yàn)槎夹枰旁诘谝恍小?/p>
-
簡單類對象的實(shí)例化過程
-
子類對象的實(shí)例化過程
多態(tài)性
JAVA中多態(tài)的兩種提現(xiàn):
- 方法的多態(tài)性:重載(相同的名稱方法實(shí)現(xiàn)不同的邏輯)开皿,方法的重寫(子類可以使用和父類相同的方法名涧黄,覆蓋掉邏輯)
- 對象的多態(tài)性:可以直接應(yīng)用在抽象類和接口上,解釋如下:
Java引用變量有兩個(gè)類型:編譯時(shí)類型和運(yùn)行時(shí)類型赋荆。編譯時(shí)類型由聲明該變量時(shí)使用的類型決定笋妥,運(yùn)行時(shí)類型由實(shí)際賦給該變量的對象決定。
若編譯時(shí)類型和運(yùn)行時(shí)類型不一致窄潭,就出現(xiàn)多態(tài)(Polymorphism)
對象的多態(tài) —在Java中,子類的對象可以替代父類的對象使用
一個(gè)變量只能有一種確定的數(shù)據(jù)類型
一個(gè)引用類型變量可能指向(引用)多種不同類型的對象
子類可看做是特殊的父類春宣,所以父類類型的引用可以指向子類的對象:向上轉(zhuǎn)型(upcasting)。
- 對象的多態(tài)之自動(dòng)類型轉(zhuǎn)換
一個(gè)引用類型變量如果聲明為父類的類型嫉你,但實(shí)際引用的是子類對象信认,那么該變量就不能再訪問子類中添加的屬性和方法,并且,對于其訪問的屬性和方法均抽,有以下特征:
- 屬性是在編譯時(shí)確定的嫁赏,編譯時(shí)e為Person類型,沒有school成員變量油挥,因而編譯錯(cuò)誤潦蝇。只能訪問父類中有的屬性款熬,且訪問的就是父類中的屬性。
- 編譯時(shí)e為Person類型攘乒,而方法的調(diào)用是在運(yùn)行時(shí)確定的贤牛,所以調(diào)用的是Student類的getInfo()方法≡蛟停——動(dòng)態(tài)綁定殉簸,只能訪問父類中有的方法,如果子類覆蓋了該方法沽讹,則在運(yùn)行時(shí)般卑,訪問的是子類覆蓋的方法。
解釋:
若子類重寫了父類方法爽雄,就意味著子類里定義的方法徹底覆蓋了父類里的同名方法蝠检,系統(tǒng)將不可能把父類里的方法轉(zhuǎn)移到子類中
對于實(shí)例變量則不存在這樣的現(xiàn)象,即使子類里定義了與父類完全相同的實(shí)例變量挚瘟,這個(gè)實(shí)例變量依然不可能覆蓋父類中定義的實(shí)例變量
- 強(qiáng)制類型轉(zhuǎn)換
強(qiáng)制類型轉(zhuǎn)換:可以把大的數(shù)據(jù)類型強(qiáng)制轉(zhuǎn)換(casting)成小的數(shù)據(jù)類型
對Java對象的強(qiáng)制類型轉(zhuǎn)換稱為造型
從子類到父類的類型轉(zhuǎn)換可以自動(dòng)進(jìn)行
從父類到子類的類型轉(zhuǎn)換必須通過造型(強(qiáng)制類型轉(zhuǎn)換)實(shí)現(xiàn)
無繼承關(guān)系的引用類型間的轉(zhuǎn)換是非法的叹谁。
-
object類
是所有JAVA類的根父類,或叫基類
object類中的主要方法:
- equlas方法:
只能比較引用乘盖,普通情況和==作用一樣焰檩,
特例:當(dāng)用equals()方法進(jìn)行比較時(shí),對類File订框、String析苫、Date及包裝類(Wrapper Class)來說,是比較類型及內(nèi)容而不考慮引用的是否是同一個(gè)對象布蔗;
原因:在這些類中重寫了Object類的equals()方法藤违。
==:
基本類型比較值:只要兩個(gè)變量的值相等浪腐,即為true.
引用類型比較引用(是否指向同一個(gè)對象):只有指向同一個(gè)對象時(shí)纵揍,==才返回true. -
String對象的創(chuàng)建
String str = "a" + new String("bc");
內(nèi)存中的情況:堆內(nèi)會(huì)創(chuàng)建new String("bc")對象, 同時(shí)會(huì)在字符串常量池內(nèi)添加"bc",”a" + "bc"會(huì)由于JVM的優(yōu)化议街,在字符串常量池內(nèi)只添加一個(gè)abc泽谨,并指向str。 - 包裝類
針對八種基本類型定義的相應(yīng)的引用類型--包裝類
基本數(shù)據(jù)類型包裝成包裝類的實(shí)例 ---裝箱
通過包裝類的構(gòu)造器實(shí)現(xiàn):
int i = 500; Integer t = new Integer(i);
還可以通過字符串參數(shù)構(gòu)造包裝類對象:
Float f = new Float(“4.56”);
Long l = new Long(“asdf”); //NumberFormatException,編譯不報(bào)錯(cuò)特漩,運(yùn)行出錯(cuò)
獲得包裝類對象中包裝的基本類型變量 ---拆箱
調(diào)用包裝類的.xxxValue()方法:
boolean b = bObj.booleanValue();
JDK1.5之后吧雹,支持自動(dòng)裝箱,自動(dòng)拆箱涂身。但類型必須匹配雄卷。
基本數(shù)據(jù)類型的包裝類之間不可以自動(dòng)轉(zhuǎn)換或強(qiáng)制轉(zhuǎn)換。
字符串轉(zhuǎn)換成基本數(shù)據(jù)類型
通過包裝類的構(gòu)造器實(shí)現(xiàn):
int i = new Integer(“12”);
通過包裝類的parseXxx(String s)靜態(tài)方法:
Float f = Float.parseFloat(“12.1”);
基本數(shù)據(jù)類型轉(zhuǎn)換成字符串
調(diào)用字符串重載的valueOf()方法:
String fstr = String.valueOf(2.34f);
更直接的方式:
String intStr = 5 + “”
- toString方法:
toString()方法在Object類中定義蛤售,其返回值是String類型丁鹉,返回類名和它的引用地址妒潭。
String類重寫了tostring方法,返回字符串的值
在進(jìn)行String和其他類型的數(shù)據(jù)進(jìn)行連接操作時(shí)揣钦,自動(dòng)調(diào)用toString方法雳灾。 - static
修飾范圍:屬性,方法冯凹,代碼塊
如果想讓一個(gè)類的所有實(shí)例共享數(shù)據(jù)(屬性或方法)谎亩,即這些數(shù)據(jù)不因?qū)ο蟮牟煌淖儯陀?strong>類變量(用static標(biāo)記)宇姚!類變量也叫做靜態(tài)變量匈庭。
作為工具的方法通常設(shè)置為靜態(tài)類。
相對的實(shí)例變量空凸,只有實(shí)例化才能使用嚎花。 - 單例設(shè)計(jì)模式
一般都是可能是構(gòu)建該對象太費(fèi)勁,或者new新對象沒必要呀洲。
所謂類的單例設(shè)計(jì)模式紊选,就是采取一定的方法保證在整個(gè)的軟件系統(tǒng)中,對某個(gè)類只能存在一個(gè)對象實(shí)例道逗,并且該類只提供一個(gè)取得其對象實(shí)例的方法兵罢。
- 如果我們要讓類在一個(gè)虛擬機(jī)中只能產(chǎn)生一個(gè)對象,我們首先必須將類的構(gòu)造方法的訪問權(quán)限設(shè)置為private滓窍,這樣卖词,就不能用new操作符在類的外部產(chǎn)生類的對象了,但在類內(nèi)部仍可以產(chǎn)生該類的對象吏夯。
- 因?yàn)樵陬惖耐獠块_始還無法得到類的對象此蜈,只能調(diào)用該類的某個(gè)靜態(tài)方法以返回類內(nèi)部創(chuàng)建的對象,靜態(tài)方法只能訪問類中的靜態(tài)成員變量噪生,所以裆赵,指向類內(nèi)部產(chǎn)生的該類對象的變量也必須定義成靜態(tài)的。
方法1 餓漢式單例模式
構(gòu)造方法私有化跺嗽,外部不可以創(chuàng)建對象
在類內(nèi)部生成一個(gè)私有的本類對象战授,使其為static
生成一個(gè)靜態(tài)的public方法,返回生成的本類對象
方法2 懶漢式單例模式(有第一個(gè)人獲取才創(chuàng)建對象)
構(gòu)造方法私有化
生成一個(gè)私有的靜態(tài)的本類變量桨嫁,初始化為Null
生成靜態(tài)的public的返回當(dāng)前類對象的方法植兰,判斷本來變量是否為Null,如果是璃吧,則實(shí)例化楣导,否則,直接返回
現(xiàn)在的懶漢式存在線程安全問題畜挨,在學(xué)習(xí)到多線程時(shí)筒繁,可以修復(fù)
- 理解main方法的語法
main方法內(nèi)傳進(jìn)去的數(shù)組彬坏,可以通過命令行模式 java TestMain abc 1w3 來傳入abc 1w3 - 類的成員之四 初始化塊
初始化塊(代碼塊)的作用:對JAVA對象進(jìn)行初始化
存在代碼塊時(shí),構(gòu)建對象膝晾,程序的執(zhí)行順序:(每創(chuàng)建一個(gè)對象栓始,都會(huì)執(zhí)行一次初始化塊)
- 聲明成員變量的默認(rèn)值
- 顯式初始化成員變量、多個(gè)初始化塊依次被執(zhí)行(同級別下按先后順序執(zhí)行)
- 構(gòu)造器再對成員進(jìn)行賦值操作
初始化塊若有修飾符血当,只能被static修飾幻赚,稱為靜態(tài)代碼塊,static代碼塊通常用來初始化靜態(tài)屬性臊旭÷淠眨或調(diào)用靜態(tài)方法
當(dāng)類被載入時(shí),類屬性的聲明和靜態(tài)代碼塊先后順序被執(zhí)行离熏,且只被執(zhí)行一次(無論創(chuàng)建幾個(gè)對象佳谦,都只執(zhí)行一次)。
非靜態(tài)代碼塊:沒有static修飾的代碼塊
1.可以有輸出語句滋戳。
2.可以對類的屬性聲明進(jìn)行初始化操作钻蔑。
3.可以調(diào)用靜態(tài)和非靜態(tài)的變量或方法。
4.若有多個(gè)非靜態(tài)的代碼塊奸鸯,那么按照從上到下的順序依次執(zhí)行咪笑。
5.每次創(chuàng)建對象的時(shí)候,都會(huì)執(zhí)行一次。且先于構(gòu)造器執(zhí)行
靜態(tài)代碼塊:用static 修飾的代碼塊
1.可以有輸出語句。
2.可以對類的屬性聲明進(jìn)行初始化操作诵盼。
3.不可以對非靜態(tài)的屬性初始化。即:不可以調(diào)用非靜態(tài)的屬性和方法扬虚。
4.若有多個(gè)靜態(tài)的代碼塊,那么按照從上到下的順序依次執(zhí)行球恤。
5.靜態(tài)代碼塊的執(zhí)行要先于非靜態(tài)代碼塊辜昵。
6.靜態(tài)代碼塊只執(zhí)行一次
代碼塊(初始化塊)的用處:
匿名內(nèi)部類:(代碼塊在這里可以代替構(gòu)造方法,因?yàn)槟涿麅?nèi)部類沒有類名碎捺,所以無法正常寫構(gòu)造方法)
- 關(guān)鍵字final
在Java中聲明類路鹰、屬性和方法時(shí)贷洲,可使用關(guān)鍵字final來修飾,表示“最終”收厨。
- final標(biāo)記的類不能被繼承。提高安全性优构,提高程序的可讀性诵叁。
String類、System類钦椭、StringBuffer類 - final標(biāo)記的方法不能被子類重寫拧额。
Object類中的getClass()碑诉。 - final標(biāo)記的變量(成員變量或局部變量)即稱為常量。名稱大寫侥锦,且只能被賦值一次进栽。
final標(biāo)記的成員變量必須在聲明的同時(shí)或在每個(gè)構(gòu)造方法中或代碼塊中顯式賦值,然后才能使用恭垦。
final和stat同時(shí)修飾的變量快毛,就是全局常量
常量定義名稱約定俗成是大寫,用_連接
- 抽象類
隨著繼承層次中一個(gè)個(gè)新子類的定義番挺,類變得越來越具體唠帝,而父類則更一般,更通用玄柏。
有時(shí)將一個(gè)父類設(shè)計(jì)得非常抽象襟衰,以至于它沒有具體的實(shí)例,這樣的類叫做抽象類粪摘。
- 用abstract修飾瀑晒,修飾類或方法
- 抽象方法只有方法的聲明,沒有方法的實(shí)現(xiàn)徘意,以分號結(jié)束
- 含有抽象方法的類必須被聲明為抽象類
- 抽象類不能被實(shí)例化瑰妄,是用來被繼承的,如果沒有重寫全部的抽象方法映砖,則子類仍為抽象類间坐。
- 不能用abstract修飾屬性,私有的邑退,靜態(tài)的竹宋,final的方法,也不能修飾構(gòu)造器地技。
- 模板方法設(shè)計(jì)模式
解決的問題:
當(dāng)功能內(nèi)部一部分實(shí)現(xiàn)是確定蜈七,一部分實(shí)現(xiàn)是不確定的。這時(shí)可以把不確定的部分暴露出去莫矗,讓子類去實(shí)現(xiàn)飒硅。
編寫一個(gè)抽象父類,父類提供了多個(gè)子類的通用方法作谚,并把一個(gè)或多個(gè)方法留給其子類實(shí)現(xiàn)三娩,就是一種模板模式。
abstract class Template{
public final void getTime(){
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("執(zhí)行時(shí)間是:"+(end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
public void code(){
for(int i = 0;i<10000;i++){
System.out.println(i);
} } }
-
接口
有了接口妹懒,就可以得到多重繼承的效果雀监。
接口(interface)是抽象方法和常量值的定義的集合。(所以可以說,接口是某些動(dòng)作的集合会前,一個(gè)類繼承某個(gè)接口好乐,也就可以說是該類新增了這些方法。
從本質(zhì)上講瓦宜,接口是一種特殊的抽象類蔚万,這種抽象類中只包含常量和方法的定義,而沒有變量和方法的實(shí)現(xiàn)临庇。
一個(gè)類可以實(shí)現(xiàn)多個(gè)接口笛坦,接口也可以繼承其它接口。
接口的特點(diǎn):
用interface來定義苔巨。
接口中的所有成員變量都默認(rèn)是由public static final修飾的版扩。
接口中的所有方法都默認(rèn)是由public abstract修飾的。
接口沒有構(gòu)造器侄泽。
接口采用多層繼承機(jī)制礁芦。
如果類沒有實(shí)現(xiàn)接口的所有方法,那么它就是抽象類悼尾。
有了抽象類柿扣,為什么還要提出接口?
如果父類想要添加新的抽象方法闺魏,那么他的子類都將受到影響未状。此時(shí)便可以讓父類實(shí)現(xiàn)一個(gè)新接口,如果子類需要該方法析桥,可以調(diào)用它或者重寫它司草。
另外,當(dāng)一個(gè)子類上有不屬于該父類類別的方法泡仗,也可以讓子類通過實(shí)現(xiàn)接口的方法添加一些方法埋虹。 -
工廠方法:
如果父類的屬性和方法已經(jīng)確定好了,子類還需要調(diào)試娩怎。程序員A需要寫子類搔课,程序員B要通過子類調(diào)用父類的穩(wěn)定方法,這時(shí)截亦,如果子類的類名等發(fā)生變化爬泥,會(huì)影響程序員B的工作,
因此可以使用工廠模式方法崩瓤,可以將所要?jiǎng)?chuàng)建的具體對象的創(chuàng)建工作延遲到子類袍啡,解決了這種緊耦合的關(guān)系。
如:創(chuàng)建一個(gè)BWM接口谷遂,各種子類BWM3,5,7實(shí)現(xiàn)好了該接口葬馋,程序員A可以寫一個(gè)工廠函數(shù)卖鲤,返回多態(tài)的BWM對象肾扰。
內(nèi)部類
解決JAVA類不能多重繼承的問題
方法:在類中寫多個(gè)內(nèi)部類去繼承許多類畴嘶,就可以在內(nèi)部類中重寫繼承類的方法,這樣集晚,使用繼承類相同的方法名和返回值以及參數(shù)列表窗悯,通過return內(nèi)部類.方法,就可以變相繼承多個(gè)類的方法偷拔。
內(nèi)部類作為類的成員的特性
可以聲明為final的
和外部類不同蒋院,Inner class可聲明為private或protected;
Inner class 可以聲明為static的莲绰,但此時(shí)就不能再使用外層類的非static的成員變量欺旧;
Inner class作為類:
可以聲明為abstract類 ,因此可以被其它的內(nèi)部類繼承
【注意】非static的內(nèi)部類中的成員不能聲明為static的蛤签,只有在外部類或static的內(nèi)部類中才可聲明static成員辞友。
匿名內(nèi)部類:
匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類震肮,只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例称龙。一個(gè)匿名內(nèi)部類一定是在new的后面,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類戳晌。