Java的三大特性是什么,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
成都地區(qū)優(yōu)秀IDC服務(wù)器托管提供商(創(chuàng)新互聯(lián)).為客戶提供專業(yè)的溫江服務(wù)器托管,四川各地服務(wù)器托管,溫江服務(wù)器托管、多線服務(wù)器托管.托管咨詢專線:18982081108
Java的三大特性:封裝、繼承、多態(tài)
Java中關(guān)于訪問權(quán)限的四個(gè)修飾符,表格如下
private | friendly(默認(rèn)) | protected | public | |
---|---|---|---|---|
當(dāng)前類訪問權(quán)限 | √ | √ | √ | √ |
包訪問權(quán)限 | × | √ | √ | √ |
子類訪問權(quán)限 | × | × | √ | √ |
其他類訪問權(quán)限 | × | × | × | √ |
其中比較尷尬的是protected修飾符,有點(diǎn)卡在中間,不上不下的感覺
因?yàn)樗贿m合用來修飾屬性
假設(shè)用它修飾屬性,那么任何一個(gè)人都可以通過繼承這個(gè)類,來直接訪問到這個(gè)類的屬性,從而破壞"封裝性"
什么是抽象類?
抽象類就是用abstract修飾,且不能被直接初始化的類,但是可以通過子類來初始化 比如:Father father = new Son()
對(duì)應(yīng)的,抽象方法就是用abstract修飾的方法
抽象方法是一種很特殊的方法,它沒有方法體,即方法實(shí)現(xiàn)代碼為空,比如abstract public void fun();
抽象方法一般在子類中進(jìn)行實(shí)現(xiàn),它就好像是在說:我不寫代碼,我只是聲明一個(gè)方法名,剩下的交給我的子孫后代(繼承類)去做
抽象類有一個(gè)很重要的特點(diǎn):抽象類可以沒有抽象方法,但是如果一個(gè)類有抽象方法,那么這個(gè)類肯定是抽象類
為什么會(huì)有抽象類
解耦,使代碼結(jié)構(gòu)更加清晰
因?yàn)槌橄箢惒荒鼙恢苯觿?chuàng)建為對(duì)象,它只是作為一個(gè)通用接口來供別人實(shí)現(xiàn)和調(diào)用,所以這樣就使得抽象的代碼更加清晰(它只聲明方法,不實(shí)現(xiàn)方法) 就好比,老板和員工,老板負(fù)責(zé)分發(fā)任務(wù),員工負(fù)責(zé)去具體的實(shí)現(xiàn)任務(wù)
好了,關(guān)于抽象類,先介紹到這里,更詳細(xì)的后面的章節(jié)再深入
重載和覆寫是兩個(gè)很容易混淆的概念
重載:同一個(gè)類中,一個(gè)方法的多種表現(xiàn)形式(參數(shù)類型不同,參數(shù)個(gè)數(shù)不同)
覆寫:繼承設(shè)計(jì)中,子類覆蓋父類的方法(也可以叫做重寫,不過這樣跟重載有點(diǎn)混淆,所以個(gè)人喜歡叫做覆寫)
他們之間的區(qū)別如下
重載 | 覆寫 | |
---|---|---|
訪問權(quán)限 | 可以不同 | 可以不同(但是子類的可見性不能比父類的低) |
方法返回值 | 可以不同 | 相同 |
參數(shù)類型 | 不同(充分條件) | 相同 |
參數(shù)個(gè)數(shù) | 不同(充分條件) | 相同 |
這里要注意幾點(diǎn)
覆寫時(shí),子類的方法訪問權(quán)限不能低于父類,比如父類方法為public,那么子類也只能為public
重載時(shí),訪問權(quán)限和方法返回值,不能作為用來判斷一個(gè)方法是否為重載的依據(jù);只能說重載允許不同的訪問權(quán)限和返回值
代碼示范如下,
// 覆寫一:正確示范 @Override public void fun(){ System.out.println("son fun"); } // 覆寫二:錯(cuò)誤示范,訪問權(quán)限低了 @Override private void fun(){ // 報(bào)錯(cuò):'fun()' in 'SonDemo' clashes with 'fun()' in 'Father'; attempting to assign weaker access privileges ('private'); was 'public' System.out.println("son fun"); }
@Override這個(gè)是干嘛的?之前沒見過啊
這個(gè)修飾符用來說明這個(gè)方法是覆寫方法,不寫也可以,系統(tǒng)會(huì)自己識(shí)別方法是不是覆寫的
那為啥還要多此一舉呢?用系統(tǒng)默認(rèn)的識(shí)別機(jī)制不好嗎?
要多此一舉;不好;
因?yàn)榧恿俗⒔猓a可讀性更高,代碼更加規(guī)范,別人看了代碼后,立馬就知道這個(gè)方法是覆寫方法
重載用圖展示可能會(huì)更加清晰
圖示解釋:
參數(shù)類型和參數(shù)個(gè)數(shù),只要滿足其一,就可以說這個(gè)方法被重載了
訪問權(quán)限和方法返回值用虛線框,是為了說明他們兩個(gè)只是重載的一個(gè)附加表現(xiàn)形式(可有可無),不能作為重載的判斷依據(jù)
下面用代碼演示下
// 基礎(chǔ)方法 public void fun1(int a){ } // 重載一:參數(shù)個(gè)數(shù)不同 public void fun1(){ } // 重載二:參數(shù)類型不同 public void fun1(float a){ } // 重載三:錯(cuò)誤示范,僅僅用訪問權(quán)限的不同來重載 private void fun1(int a){ // 編譯報(bào)錯(cuò):'fun1(int)' is already defined } // 重載四:錯(cuò)誤示范,僅僅用返回值的不同來重載 public int fun1(int a){ // 編譯報(bào)錯(cuò):'fun1(int)' is already defined return 0; }
下面進(jìn)入正文,開始順序介紹這三大特性
就是把類的屬性私有化(private修飾),再通過公有方法(public)進(jìn)行訪問和修改
為什么要封裝呢?
追蹤變化:可以在set方法中,編寫代碼來追蹤屬性的改變記錄
public void setName(String name) { System.out.println("名字即將被修改"); System.out.println("舊名字:" + this.name); System.out.println("新名字:" + name); this.name = name; }
修改底層實(shí)現(xiàn):在修改屬性名時(shí),不會(huì)影響外部接口對(duì)屬性的訪問
比如:name屬性改為firstName和lastName,name就可以在get方法中修改返回值為firstName+lastName,對(duì)外接口沒變化
// 修改前 private String name; public String getName() { return name; } // 修改后 private String firstName; private String lastName; // 方法名不用變,只是方法內(nèi)容作了修改 public String getName() { return firstName + lastName; }
校驗(yàn)數(shù)據(jù):可以在set方法中,校驗(yàn)傳來的數(shù)據(jù)是否符合屬性值的設(shè)定范圍,防止無效數(shù)據(jù)的亂入
public void setAge(int age) throws Exception { if(age>1000 || age<0){ throw new Exception("年齡不符合規(guī)范,0~1000"); } this.age = age; }
如果子類繼承了父類,那么子類就可以復(fù)用父類的方法和屬性,并且可以在此基礎(chǔ)上新增方法和屬性
這里要注意的一點(diǎn)是:Java是單繼承語言,即每個(gè)類只能有一個(gè)父類
這里還要普及一個(gè)常識(shí):如果一個(gè)類沒有指定父類(即沒有繼承任何類),那么這個(gè)類默認(rèn)繼承Object類
為什么要用繼承呢?
為了代碼復(fù)用,減少重復(fù)工作
單繼承不會(huì)太局限嗎?為啥不用多繼承?
因?yàn)槎嗬^承會(huì)導(dǎo)致"致命方塊"問題(因?yàn)橄駬淇伺频姆綁K符號(hào))
比如A同時(shí)繼承B和C,然后B和C各自繼承D
B和C各自覆寫了D的fun方法
那這時(shí)A該調(diào)用哪個(gè)類的fun方法呢
下面用圖來說話
那為什么叫致命方塊,而不是致命三角形呢?那個(gè)D類好像是多余的
不多余
這個(gè)D類其實(shí)就是上面講到的抽象類的作用:將共有的部分fun()
抽象出來(或者提供一個(gè)基礎(chǔ)的實(shí)現(xiàn)),然后子類分別去實(shí)現(xiàn)各自的,這也是多態(tài)的一種體現(xiàn)(下面會(huì)將多態(tài))
如果沒有D類,那么B和C的fun()
就會(huì)存在重復(fù)代碼,這時(shí)你可能就想要搞一個(gè)父類出來了,這個(gè)父類就是D類
那要怎么判斷繼承類設(shè)計(jì)得好不好呢?
通過is-a關(guān)系來判斷
is-a關(guān)系指的是一個(gè)是另一個(gè)的關(guān)系,男人是人(說得通),人是男人(一半說得通)
用is-a關(guān)系可以很好地體現(xiàn)你的繼承類設(shè)計(jì)的好還是壞
如果子類都可以說是一個(gè)父類,那么這個(gè)繼承關(guān)系設(shè)計(jì)的就很好(男人是人,is-a關(guān)系)
如果子類和父類只是包含或者引用的關(guān)系,那么這個(gè)繼承關(guān)系就很糟糕(貓是貓籠,包含關(guān)系)
有沒有什么辦法可以阻止類的繼承?就像private修飾符用來封裝屬性,其他人訪問不到一樣
有啊,final修飾符可以阻止類的繼承
這里重點(diǎn)講一下final修飾符
final可以用來修飾屬性、方法、類,表示他們是常量,不可被修改的
final修飾屬性:屬性是常量,必須在定義時(shí)初始化,或者構(gòu)造函數(shù)中初始化
final修飾方法:方法不能被覆寫
final修飾類:類不能被繼承
說到final,有必要提一下內(nèi)聯(lián)
內(nèi)聯(lián)指的是,如果一個(gè)方法內(nèi)容很短,且沒有被其他類覆寫時(shí),方法名會(huì)被直接替換為方法內(nèi)容
比如:final getName()這個(gè)方法可以內(nèi)聯(lián)為name屬性
再比如:getSum(){return a+b},會(huì)直接被內(nèi)聯(lián)為a+b
為什么會(huì)有內(nèi)聯(lián)這個(gè)東西呢?
因?yàn)檫@樣可以提高效率(細(xì)節(jié):CPU在處理方法調(diào)用的指令時(shí),使用的分支轉(zhuǎn)移會(huì)擾亂預(yù)取指令的策略,這個(gè)比較底層,這里先簡(jiǎn)單介紹,后面章節(jié)再深入)
那它有沒有什么缺點(diǎn)呢?
有,如果一個(gè)方法內(nèi)容過長,又誤被當(dāng)做內(nèi)聯(lián)處理,那么就會(huì)影響性能
比如你的代碼多個(gè)地方都調(diào)用這個(gè)方法,那么你的代碼就會(huì)膨脹變得很大,從而影響性能
那有沒有辦法可以解決呢?
有,虛擬機(jī)的即時(shí)編譯技術(shù)
即時(shí)編譯會(huì)進(jìn)行判斷,如果一個(gè)方法內(nèi)容很長,且被多次調(diào)用,那么它會(huì)自動(dòng)關(guān)閉內(nèi)聯(lián)機(jī)制,防止代碼膨脹
字面理解,就是多種形態(tài),在Java中,多態(tài)指的是,一個(gè)類可以有多種表現(xiàn)形態(tài)
多態(tài)主要是 用來創(chuàng)建可擴(kuò)展的程序
像我們上面提到的繼承就是屬于多態(tài)的一種
還有一種就是接口(interface)
接口類一種是比抽象類更加抽象的類
因?yàn)槌橄箢惼鸫a還可以實(shí)現(xiàn)方法,但是接口類沒得選,就只能定義方法,不能實(shí)現(xiàn)
不過從Java8開始,接口支持定義默認(rèn)方法和靜態(tài)方法
接口的默認(rèn)方法(default修飾符)和靜態(tài)方法(static修飾符),會(huì)包含方法內(nèi)容,這樣別人可以直接調(diào)用接口類的方法(后面章節(jié)再細(xì)講)
這樣你會(huì)發(fā)現(xiàn)接口變得很像抽象類了,不過接口支持多實(shí)現(xiàn)(即一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)類,但是一個(gè)類同時(shí)只能繼承一個(gè)類)
這樣一來,Java相當(dāng)于間接地實(shí)現(xiàn)了多繼承
下圖說明繼承和實(shí)現(xiàn)的區(qū)別:?jiǎn)卫^承,多實(shí)現(xiàn)
多態(tài)一般用在哪些場(chǎng)景呢?
場(chǎng)景很多,這里說兩個(gè)最常用的
場(chǎng)景一:方法的參數(shù),即方法定義時(shí),父類作為方法的形參,然后調(diào)用時(shí)傳入子類作為方法的實(shí)參
場(chǎng)景二:方法的返回值,即方法定義時(shí),父類作為方法的返回值,然后在方法內(nèi)部實(shí)際返回子類
代碼示范如下:
public class PolyphorismDemo { public static void main(String[] args) { PolyphorismDemo demo = new PolyphorismDemo(); //場(chǎng)景一:形參,將貓(子類)賦值給動(dòng)物(父類) demo.fun(new Cat()); //場(chǎng)景二:返回值,將貓賦值給動(dòng)物 Animal animal = demo.fun2(); } public void fun(Animal animal){ } public Animal fun2(){ return new Cat(); } } class Animal{ } class Cat extends Animal{ }
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
標(biāo)題名稱:Java的三大特性是什么
文章地址:http://vcdvsql.cn/article6/pdhiog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、網(wǎng)站收錄、網(wǎng)站設(shè)計(jì)公司、外貿(mào)網(wǎng)站建設(shè)、商城網(wǎng)站、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)