繼承
在此之前裂问,我要寫一個比較重要的一點遭顶,在JAVA核心教程和head of JAVA中都提到的张峰,單例設(shè)計模式,它的好處就是可以保證一個類在內(nèi)存中的對象唯一性棒旗。喘批。單例設(shè)計模式又可以分為懶漢式和餓漢式兩種,前者是在類加載到方法區(qū)的時候直接生成一個對象铣揉,餓漢式是在需要的時候再創(chuàng)建一個對象饶深。
所謂單例,就是這個類能且僅能初始化一個實例對象逛拱。怎么去實現(xiàn)呢敌厘?那就是阻止類以外的地方去創(chuàng)建對象,我在類中就直接創(chuàng)建好對象橘券。private構(gòu)造器就可以使得類外無法創(chuàng)建對象额湘,然后通過new 在本類中創(chuàng)建一個本類對象,定義一個公有的方法旁舰,將創(chuàng)建的對象返回锋华。
/**
懶漢式
@author Jason c
@version 1.0
*/
class TestObject2
{
private static TestObject2 instance;
private TestObject2(){}
public static TestObject2 getInstance()
{
if(instance==null)
instance=new TestObject2();
return instance;
}
}
/*
餓漢式
*/
class single2
{
private static single2 instance=new single2();
private single2() {}
public static single2 getInstance()
{
return instance;
}
}
如何實現(xiàn)繼承呢?
java提供了關(guān)鍵字:extends
格式:class 子類 extends 父類{}
好處:A.提高了代碼的復(fù)用性箭窜,提高了代碼的可維護性毯焕,讓類與類之間產(chǎn)生了關(guān)系,從而為多態(tài)提供了前提
類和類之前產(chǎn)生關(guān)系磺樱,其實也是繼承的弊端:類和類之前的耦合性增強了
開發(fā)的原則:低耦合纳猫,高內(nèi)聚
耦合:類與類之前的關(guān)系
內(nèi)聚:就是自己完成某件事的能力
java不支持多繼承,單支持多級繼承
繼承的注意事項:
子類只能繼承父類所有非私有的成員(成員變量和成員方法)
子類不能繼承父類的構(gòu)造方法竹捉,但是可以通過“super”關(guān)鍵字去訪問父類的構(gòu)造方法
不能因為部分功能而去繼承
什么時候使用繼承芜辕?
繼承其實體現(xiàn)的是一種關(guān)系,"is a"
只要符合這種邏輯關(guān)系块差,就可以使用繼承
繼承中侵续,成員變量之間的關(guān)系
在子類方法中訪問一個變量的查找順序
1.在子類方法的局部范圍找,有就使用
2.在子類的成員范圍找憨闰,有就使用
3.在父類的成員范圍找状蜗,有就使用
4.如果還找不到,報錯
this和super的區(qū)別?
分別是什么呢?
this代表本類對應(yīng)的引用鹉动。
super代表父類存儲空間的標(biāo)識(可以理解為父類引用,可以操作父類的成員)
怎么用呢?
A:調(diào)用成員變量
this.成員變量 調(diào)用本類的成員變量
super.成員變量 調(diào)用父類的成員變量
B:調(diào)用構(gòu)造方法
this(...) 調(diào)用本類的構(gòu)造方法
super(...) 調(diào)用父類的構(gòu)造方法
C:調(diào)用成員方法
this.成員方法 調(diào)用本類的成員方法
super.成員方法 調(diào)用父類的成員方法
繼承中構(gòu)造方法的關(guān)系
子類中所有的構(gòu)造方法都會訪問父類的無參構(gòu)造方法 因為子類會繼承父類的數(shù)據(jù)轧坎,可能還會使用父類的數(shù)據(jù),所以子類初始化之前泽示,一定要完成父類數(shù)據(jù)的初始化(默認(rèn)有一句super();)
子類每一個構(gòu)造方法的第一條語句默認(rèn)都是:super();
如果父類中只有一個有參的構(gòu)造方法缸血,在子類的構(gòu)造方法必須調(diào)用蜜氨,而且是子類的構(gòu)造方法第一句話必須是調(diào)用父類的有參構(gòu)造方法,否則編譯器會提示錯誤的属百。如果父類中有無參的構(gòu)造方法记劝,沒有寫的話,會自動調(diào)用的族扰,也就不會報錯厌丑。
**注意:super(...) 其中,"..."是需要載入的參數(shù)渔呵,即父類的有參構(gòu)造函數(shù)的參數(shù)值怒竿,并非參數(shù)的變量名。
如果父類沒有無參構(gòu)造方法扩氢,那么子類的構(gòu)造方法會出現(xiàn)什么現(xiàn)象呢?
報錯耕驰。
如何解決呢?
A:在父類中加一個無參構(gòu)造方法
B:通過使用super關(guān)鍵字去顯示的調(diào)用父類的帶參構(gòu)造方法
C:子類通過this去調(diào)用本類的其他構(gòu)造方法
子類中一定要有一個去訪問了父類的構(gòu)造方法,否則父類數(shù)據(jù)就沒有初始化录豺。
注意事項:
this(...)或者super(...)必須出現(xiàn)在第一條語句上朦肘。
如果不是放在第一條語句上,就可能對父類的數(shù)據(jù)進行了多次初始化双饥,所以必須放在第一條語句上媒抠。
子類初始化之前先初始化父類
方法重寫:子類中出現(xiàn)了和父類中方法聲明一模一樣的方法。
方法重載:
本類中出現(xiàn)的方法名一樣咏花,參數(shù)列表不同的方法趴生。與返回值無關(guān)。
子類對象調(diào)用方法的時候:
先找子類本身昏翰,再找父類苍匆。
方法重寫的應(yīng)用:
當(dāng)子類需要父類的功能,而功能主體子類有自己特有內(nèi)容時棚菊,可以重寫父類中的方法浸踩。
這樣,即沿襲了父類的功能统求,又定義了子類特有的內(nèi)容检碗。
案例:
A:定義一個手機類。
B:通過研究球订,我發(fā)明了一個新手機后裸,這個手機的作用是在打完電話后瑰钮,可以聽天氣預(yù)報冒滩。
按照我們基本的設(shè)計,我們把代碼給寫出來了浪谴。
但是呢?我們又發(fā)現(xiàn)新手機應(yīng)該是手機开睡,所以因苹,它應(yīng)該繼承自手機。
其實這個時候的設(shè)計篇恒,并不是最好的扶檐。
因為手機打電話功能,是手機本身就具備的最基本的功能胁艰。
所以款筑,我的新手機是不用在提供這個功能的。
但是腾么,這個時候奈梳,打電話功能就沒有了。這個不好解虱。
最終攘须,還是加上這個功能。由于它繼承了手機類殴泰,所以于宙,我們就直接使用父類的功能即可。
那么悍汛,如何使用父類的功能呢?通過super關(guān)鍵字調(diào)用
方法重寫的注意事項:
父類的私有方法不可以被重寫
子類重寫父類方法的時候捞魁,權(quán)限不可以更低,假如父類方法是public员凝,子類重寫后不可以變成private
類靜態(tài)方法署驻,子類也必須靜態(tài)方法
final關(guān)鍵字
繼承的代碼體現(xiàn)
由于繼承中方法有一個現(xiàn)象:方法重寫
所以,父類的功能健霹,就會被子類給覆蓋掉
有些時候旺上,我們不想讓子類去覆蓋掉父類的功能,只能讓他使用糖埋。
這個時候宣吱,針對這種情況,Java就提供了一個關(guān)鍵字:final
final:顧名思義瞳别,最終的意思征候,常見的是它可以修飾類
當(dāng)final修飾局部變量的時候,變量值無法改變
因此當(dāng)局部變量為一般數(shù)據(jù)類型的時候祟敛,局部變量==常量(值不變)
當(dāng)局部變量為引用數(shù)據(jù)類型的時候疤坝,局部變量==常量(值不變),此時的值是地址值馆铁,引用數(shù)據(jù)類型本身就是引用一個地址值跑揉,地址指向對象。
多態(tài)
多態(tài)是同一個對象,在不同時刻表現(xiàn)出來的不同狀態(tài)历谍。
多態(tài)的前提:
1.要有繼承關(guān)系
2.要有方法重寫
其實沒有也是可以的现拒,但是如果沒有這個就沒有意義。
3.要有父類引用指向子類對象望侈。
多態(tài)中的成員訪問特點:
1.成員變量
編譯看左邊印蔬,運行看左邊。
2.構(gòu)造方法
創(chuàng)建子類對象的時候脱衙,訪問父類的構(gòu)造方法侥猬,對父類的數(shù)據(jù)進行初始化。
3.成員方法
編譯看左邊捐韩,運行看右邊陵究。 (因為方法被覆蓋了)
4.靜態(tài)方法
編譯看左邊,運行看左邊奥帘。
靜態(tài)和類相關(guān)铜邮,算不上重寫,所以還是左邊的
結(jié)論:由于成員方法存在方法重寫寨蹋,所以它運行看右邊松蒜,其他都是看左邊
解析:
先看代碼:
class Cat extends animals
{
int num=1;
}
class Dog extends animals
{
int num=2;
int num2=3;
public void Test ()
{
System.out.println(num);
}
}
class animals
{
int num=3;
}
public class Test {
public static void main(String[] args)
{
Dog D= new Dog();//創(chuàng)建一個Dog類的實例對象和Dog類的引用變量D,D指向Dog的實例對象
animals a=D;//創(chuàng)建父類的引用變量a,指向引用變量D已旧;
System.out.println(a.num2)//測試此時引用變量a是否可以獲得子類的成員變量num2
a.Test(); //測試此時引用變量a是否可以獲得子類的方法Test()
}
}
運行結(jié)果是秸苗,報錯,animals類中不含有Test()方法和成員變量num2运褪。
總結(jié)惊楼,當(dāng)引用變量為父類,指向子類的實例對象的時候秸讹,此時父類的引用變量就像是遙控器檀咙,上面的按鍵的功能只有父類擁有的,其他的“按不到”璃诀。
那么弧可,如果此時我想使用子類的特有功能怎么辦?
Dog D2=a?
一定會報錯
因為向下轉(zhuǎn)型必須要通過強制類型轉(zhuǎn)換劣欢,因為其實它還是Dog對象棕诵,只是被聲明為animals類型。格式是Dog D2=(Dog)a凿将,這樣就不會報錯
一個非常經(jīng)典的多態(tài)小程序
多態(tài)的問題理解:
class 孔子爹 {
public int age = 40;
public void teach() {
System.out.println("講解JavaSE");
}
}
class 孔子 extends 孔子爹 {
public int age = 20;
public void teach() {
System.out.println("講解論語");
}
public void playGame() {
System.out.println("英雄聯(lián)盟");
}
}
//Java培訓(xùn)特別火,很多人來請孔子爹去講課校套,這一天孔子爹被請走了
//但是還有人來請,就誓恋郑孔子在家笛匙,價格還挺高。孔子一想膳算,我是不是可以考慮去呢?
//然后就穿上爹的衣服,帶上爹的眼睛弛作,粘上爹的胡子涕蜂。就開始裝爹
//向上轉(zhuǎn)型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //講解論語
//k爹.playGame(); //這是兒子才能做的
//講完了,下班回家了
//脫下爹的裝備映琳,換上自己的裝備
//向下轉(zhuǎn)型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //講解論語
k.playGame(); //英雄聯(lián)盟
不管怎么樣机隙,程序的入口只能是main,因此在類加載后萨西,
應(yīng)從public static void main(String[] args)開始順序執(zhí)行有鹿。