詳細(xì)理解JAVA面向?qū)ο蟮姆庋b,繼承,多態(tài),抽象
創(chuàng)建類的對(duì)象 = 類的實(shí)例化 = 實(shí)例化類
類和對(duì)象的使用(面向?qū)ο笏枷肼涞氐膶?shí)現(xiàn)):
1.創(chuàng)建類,設(shè)計(jì)類的成員
2.創(chuàng)建類的對(duì)象
3.通過“對(duì)象.屬性”或“對(duì)象.方法”調(diào)用對(duì)象的結(jié)構(gòu)
如果創(chuàng)建了一個(gè)類的多個(gè)對(duì)象,則每個(gè)對(duì)象都獨(dú)立的擁有一套類的屬性。(非static的)
意味著,如果我們修改一個(gè)對(duì)象的屬性a,則不影響另外一個(gè)對(duì)象屬性a的值。
子類對(duì)象實(shí)例化的全過程
1.從結(jié)果上看:(繼承性)
- 子類繼承父類以后,就獲取了父類中聲明的屬性和方法。
- 創(chuàng)建子類的對(duì)象,在對(duì)空間中,就會(huì)加載所有父類中聲明的屬性。
2.從過程上來看:
當(dāng)我們通過子類的構(gòu)造器創(chuàng)建子類對(duì)象時(shí),我們一定會(huì)直接或間接的調(diào)用其父類的構(gòu)造器,進(jìn)而調(diào)用父類的父類的構(gòu)造器。直到調(diào)用了java.lang.Object類中空參的構(gòu)造器為止。正因?yàn)榧虞d過所有的父類的結(jié)構(gòu),所以才可以看到內(nèi)存中有父類的結(jié)構(gòu),子類對(duì)象才可以考慮進(jìn)行調(diào)用。
明確:雖然創(chuàng)建子類對(duì)象時(shí),調(diào)用了父類的構(gòu)造器,但是自始至終就創(chuàng)建過一個(gè)對(duì)象,即為new的子類對(duì)象。
匿名對(duì)象
1. 理解:我們創(chuàng)建的對(duì)象,沒有顯式的賦給一個(gè)變量名,即為匿名對(duì)象
class Phone{ Phone p = new phone();//普通方式創(chuàng)建對(duì)象 p.sendEmail(); new Phone().sendEmail();//匿名對(duì)象只能直接調(diào)用方法 new Phone().price = 1999;//匿名對(duì)象調(diào)用屬性 }
2.特征:匿名對(duì)象只能使用一次
3.匿名對(duì)象在開發(fā)中的使用
class Phone{ public static void main(String[] args){ PhoneMall mall = new PhoneMall(); //匿名對(duì)象的使用 mall.show(new Phone()); } } class PhoneMall{ public void show(Phone phone){ phone.sendEmail(); } }
1.封裝性
封裝性的體現(xiàn):
我們將類的屬性xxx私有化(private),同時(shí),提供公共的(public)方法來獲取(getXxx)和設(shè)置屬性
拓展:封裝性的體現(xiàn):A. 如上 B.不對(duì)外暴露的私有的方法 C.單例模式.....
封裝性的體現(xiàn),需要權(quán)限修飾符來配合。
1. Java規(guī)定的4中權(quán)限(從小到大排列):private、缺省、protected、public
2. 4種權(quán)限修飾符可以用來修飾類的內(nèi)部結(jié)構(gòu):屬性、方法、構(gòu)造器、內(nèi)部類
3. 修飾類的話,只能使用:缺省、public; public類可以在任意地方被訪問。
default類只可以被同一個(gè)包內(nèi)部的類訪問。
2.繼承性
繼承性的格式:class A extends B{}
A:子類、派生類、subclass
B:父類、超類、基類、superclass
體現(xiàn):一旦子類A繼承父類B以后,子類A中就獲取了父類B中聲明的所有的屬性和方法。
特別的,父類中聲明為private的屬性和方法,子類繼承父類以后,仍然認(rèn)為獲取了父類中私有的結(jié)構(gòu)。只是由于封裝性的影響,使得子類不能直接調(diào)用父類的結(jié)構(gòu)而已。
子類繼承父類以后,還可以聲明自己特有的屬性或方法,實(shí)現(xiàn)功能的擴(kuò)展。子類和父類的關(guān)系,不同于子集和集合的關(guān)系。
Java中關(guān)于繼承性的規(guī)定:
1.一個(gè)類可以被多個(gè)子類繼承。
2.Java中類的單繼承性,一個(gè)類只能有一個(gè)父類
3.子父類是相對(duì)的概念。
4.之類直接繼承的父類,稱為:直接父類;間接繼承的父類稱為:間接父類
5.子類繼承父類以后,就獲取了直接父類以及所有間接父類中生命的屬性和方法
----------
1.如果我們沒有顯示的聲明一個(gè)列的父類的話,則此類繼承于java.lang.Object類
2.所有的java類(除java.lang.Object類之外)都直接或間接的繼承于java.lang.Object類
3.意味著,所有的java類具有java.lang.Object類聲明的功能。
繼承性的好處:
減少了代碼的冗余,提高了代碼的復(fù)用性便于功能的擴(kuò)展;為之后多態(tài)性的使用,提供了前提。
在使用子類實(shí)例時(shí),如果我們想要使用某些父類的屬性或方法,可以借助構(gòu)造器和封裝方法;如下:
public class Father{ //父類中的私有的屬性 private double ownMoney = 2000;//私房錢 //父類中的受保護(hù)的屬性 protected double money = 5000; //父類中的公開屬性 public String name = "老張"; }
public class Son extends Father{ //子類中的獨(dú)有屬性 ... //使用構(gòu)造器為屬性賦值 public Son(String name,double money){ super.name = name; super.money = money; } //使用封裝方法操作父類中的屬性 public void setMoney(double money){ super.money = money; } public double getMoney(){ return super.money; } }
public class Test{ public static void main(String[] args){ //在test包中的Test類中創(chuàng)建Son實(shí)例 Son son = new Son("小張",3000);//為父類繼承而來的屬性賦值 //以下代碼編譯通過 double money = son.getMoney(); System.out.println(money); son.setMoney(money - 500); } }
從以上的例子看到:測(cè)試類對(duì)于字符類來說是一個(gè)處在不同包中的完全無關(guān)的類,在調(diào)用時(shí)會(huì)被權(quán)限修飾符所限制,所以這里明確一下:權(quán)限修飾符是根據(jù)類的搜在路徑 與列之間的結(jié)構(gòu)關(guān)系驚醒限定的,不是說在任意一個(gè)地方使用子類實(shí)例都能調(diào)用出父類中的屬性和方法。
3.多態(tài)性
1.理解多態(tài)性:可以理解為一個(gè)事物的多種形態(tài)。
2.何為多態(tài)性:
- 對(duì)象的多態(tài)性:父類的引用指向子類的對(duì)象(或子類的對(duì)象賦給父類的引用)
3.多態(tài)的使用:虛擬方法調(diào)用
- 有了對(duì)象的多態(tài)性以后,我們?cè)诰幾g期,只能調(diào)用父類中聲明的方法,但在運(yùn)行期,我們實(shí)際執(zhí)行的是子類重寫父類的方法。
總結(jié):編譯,看左邊;運(yùn)行,看右邊。
4.多態(tài)性的使用前提:A.存在子父類繼承關(guān)系 B.子類重寫父類的方法 C.父類引用指向子類對(duì)象
5.對(duì)象的多態(tài)性,只適用于方法,不適用于屬性(編譯和運(yùn)行都看左邊)
5.1 若子類重寫了父類方法,就意味著子類里定義的方法徹底覆蓋了父類里的同名方法,系統(tǒng)將不可能把父類里的方法轉(zhuǎn)移到子類中,編譯看左邊,運(yùn)行看右邊。
5.2 對(duì)于實(shí)例變量則不存在這樣的現(xiàn)象,即使子類里定義了與父類完全相同的實(shí)例變量,這個(gè)實(shí)例變量依然不可能覆蓋父類中定義的實(shí)例變量,編譯運(yùn)行都看左邊。
6.多態(tài)的使用:當(dāng)調(diào)用子父類同名同參數(shù)的方法時(shí),實(shí)際執(zhí)行的是子類重寫父類的方法----->虛擬方法調(diào)用
虛擬方法調(diào)用
正常的方法調(diào)用:
Person e = new Person(); e.getInfo(); Student e = new Student(); e.getInfo();
虛擬方法調(diào)用(多態(tài)情況下)
子類中定義了與父類同名同參數(shù)的方法,在多態(tài)情況下,將此時(shí)父類的方法稱為虛擬方法,父類根據(jù)賦給它的不同子類對(duì)象,動(dòng)態(tài)調(diào)用屬于子類的該方法,這樣的方法調(diào)用在編譯期是無法確定的。
Person e = new Student(); e.getInfo();//調(diào)用Student類的getInfo()方法
編譯時(shí)類型和運(yùn)行時(shí)類型
編譯時(shí)e為Person類型,而方法的調(diào)用時(shí)在運(yùn)行時(shí)確定的,所以調(diào)用的是Student類的getInfo()方法。------動(dòng)態(tài)綁定
public class PersonTest{ public static void main(String[] args){ Person p2 = new Man(); Person p3 = new Woman(); p2.name = "Tom"; //不能調(diào)用子類所特有的方法、屬性;編譯時(shí),p2是Person類型。 // p2.earnMoney();//earnMoney()是子類Man()的方法 } }
有了對(duì)象的多態(tài)性以后,內(nèi)存中實(shí)際上是加載了子類特有的屬性和方法的,但是由于變量聲明為父類類型,導(dǎo)致編譯時(shí),只能調(diào)用父類中聲明的屬性和方法,子類特有的屬性和方法不能調(diào)用。
如何才能調(diào)用子類特有的屬性和方法?
答:向下轉(zhuǎn)型,使用強(qiáng)制類型轉(zhuǎn)換符。
Man m1 = (Man)p2; m1.earnMoney(); //使用強(qiáng)轉(zhuǎn)時(shí),可能出現(xiàn)ClassCastException的異常 Woman w1 = (Woman)p2;//p2是Man;兩者并列關(guān)系 w1.goShopping();
解決這個(gè)問題的辦法是先使用關(guān)鍵字(instanceof)判斷一下?。。。?! (會(huì)在下一篇博客關(guān)鍵字中介紹)
4.抽象性
背景:有兩個(gè)在邏輯上看似相關(guān)的類,我們想要把他們聯(lián)系起來,因?yàn)檫@樣做可以提高效率,例如:矩形、圓形,都可以具有周長(zhǎng)和面積兩個(gè)方法,但是計(jì)算的方式完全不同,矩形和圓形之間肯定不能構(gòu)成子父類的關(guān)系,那么只能是同時(shí)去繼承一個(gè)父類。這時(shí),就引出了抽象的概念。
1.抽象類的特點(diǎn):
抽象類的本質(zhì)依然是一個(gè)類,所以具備著一個(gè)普通類的所有功能,包括構(gòu)造方法等的定義,總結(jié)一下,抽象類具有以下的幾個(gè)特點(diǎn):
- A. 抽象類由abstract修飾
- B. 抽象類中允許出現(xiàn)抽象方法
- C.抽象了不能通過構(gòu)造器直接實(shí)例化
- D.可以在抽象類中定義普通方法供子類繼承。
public abstract class Figure{ //定義計(jì)算周長(zhǎng)的抽象方法:getC() //抽象方法,不能有方法主體 public abstract double getC(); }
2.天生的父類:抽象類
2.1 抽象類不能直接實(shí)例化(編譯無法通過),是天生的父類
2.2 如果一個(gè)類繼承了抽象類,那么必須重寫父類中的抽象方法
2.3 如果抽象類中定義了構(gòu)造方法,可以被子類調(diào)用或在實(shí)例化子類對(duì)象時(shí)執(zhí)行
2.4 如果抽象類的子類依然是抽象類(需要用abstract聲明),可以不重寫抽象方法,將重寫操作留給下一級(jí)子類
2.5 抽象類不能使用final關(guān)鍵字修飾,因?yàn)閒inal 修飾的類是無法被繼承
2.6 抽象類的匿名子類
public class PersonTest{ public static void main(String[] args){ method(new Student());//匿名對(duì)象 Worker worker = new Worker(); method1(worker);//非匿名的類非匿名的對(duì)象 method1(new Worker());//非匿名的類匿名的對(duì)象 //創(chuàng)建了一匿名子類的對(duì)象:p Person p = new Person(){ @Override public void eat(){ } } //創(chuàng)建匿名子類的匿名對(duì)象 method1(new Person()){ @Override public void eat(){ } } } } class Worker extends Person{ }
3.抽象方法
3.1 抽象類中的抽象方法只是聲明,不包含方法體
3.2 抽象方法不能用private修飾,因?yàn)槌橄蠓椒ū仨毐蛔宇悓?shí)現(xiàn)(重寫),而private 權(quán)限對(duì)于子類來說是不能訪問的
3.3 一個(gè)類繼承了一個(gè)抽象類,那么它必須全部重寫抽象類中的抽象方法,當(dāng)然也可以不全部重寫,如果不重寫全部抽 象方法則這個(gè)子類也必須是抽象類
3.4 構(gòu)造方法,類方法(static修飾的方法)不能聲明為抽象方法
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
詳談HashMap和ConcurrentHashMap的區(qū)別(HashMap的底層源碼)
下面小編就為大家?guī)硪黄斦凥ashMap和ConcurrentHashMap的區(qū)別(HashMap的底層源碼)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08Java統(tǒng)計(jì)字符串中字符出現(xiàn)次數(shù)的方法示例
這篇文章主要介紹了Java統(tǒng)計(jì)字符串中字符出現(xiàn)次數(shù)的方法,涉及Java針對(duì)字符串的遍歷、查找、計(jì)算等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12Java?Stream函數(shù)式編程管道流結(jié)果處理
這篇文章主要為大家介紹了Java?Stream函數(shù)式編程管道流結(jié)果處理的示例過程解析需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03一次mybatis連接查詢遇到的坑實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于一次mybatis連接查詢遇到的坑的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12SpringBoot整合Netty實(shí)現(xiàn)WebSocket的示例代碼
本文主要介紹了SpringBoot整合Netty實(shí)現(xiàn)WebSocket的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05利用Postman和Chrome的開發(fā)者功能探究項(xiàng)目(畢業(yè)設(shè)計(jì)項(xiàng)目)
這篇文章主要介紹了利用Postman和Chrome的開發(fā)者功能探究項(xiàng)目(畢業(yè)設(shè)計(jì)項(xiàng)目),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12