Java基础以及与C++的一些对比
這兩天回憶一些Java基礎(chǔ),感覺自己很多地方都不是很牢固,也花費(fèi)在不少時間和不少流量在手機(jī)上查資料。
還是寫下來這些東西以免再忘記。
同時還是要記住多動手,編程最重要的就是動手敲啊,有想法有疑問就要自己去實現(xiàn)去驗證。
1. 訪問控制
Java的默認(rèn)訪問權(quán)限(包訪問權(quán)限)跟C++中的友元很像其實,都具有一定的特殊性。
同一個包中的類是可以任意訪問其他類的非私有成員的,而如果繼承關(guān)系發(fā)生在同一個包中,子類繼承的所有非私有成員都是可見的。
但如果繼承不是發(fā)生在同一個包中則會有很大不同,通過繼承導(dǎo)入的包,子類只有繼承的保護(hù)和公有成員才是可見的。
導(dǎo)入的包只能導(dǎo)入該包內(nèi)的公有類和該公有類的公有成員,保護(hù)成員在子類中可見,但即使在子類中也不能通過父類對象來訪問保護(hù)成員,只能通過子類訪問繼承后的保護(hù)成 員。
繼承發(fā)生的時候其實子類都會繼承父類的所有成員,不管是私有保護(hù)或者公有,只是訪問修飾符不同導(dǎo)致了可見性的不同。
C++中的友元,允許訪問友元類的所有變量,包括私有變量包括通過對象或?qū)ο笞鳛楹瘮?shù)引用參數(shù)訪問。在子類中是不可以通過對象訪問父類的保護(hù)成員的。只有公有成員可以通過對象或?qū)ο笾羔樤L問。
C++有三種繼承方式,最常用的還是public繼承,而且Java直接閹割了其他的兩種繼承方式。
? ?關(guān)于類成員的protected權(quán)限,其實是很值得琢磨的我覺得。
介于private和public之間,在Java中,在同一個包內(nèi)發(fā)生的繼承就不說了,除了非私有成員其他類(包括子類)都可以任意訪問,包括通過對象訪問,子類繼承的除非私有成員外也都具有可見性。和如果在不同包下的繼承,在子類中就沒有辦法通過父類對象訪問protected成員,在這一點上和C++還是很像,C++中子類是沒有辦法通過父類對象訪問父類的保護(hù)成員的。
?
?
關(guān)于訪問控制,其實OOP思想的語言都大同小異,不管是Java,C++,還是C#。
2. 抽象類與接口
抽象類中可以沒有抽象方法,但具有抽象方法的類必須定義為抽象類,抽象類不能實例化。
接口中的變量自動具有public static final屬性,接口中的方法自動具有public abstract屬性,接口允許多繼承。
C++中含有純虛函數(shù)的類稱為虛基類,和Java中的接口比較像,但虛基類中的函數(shù)除了純虛函數(shù)都可以有自己的實現(xiàn),虛基類同樣不能實例化。純虛函數(shù)不能有自己的函數(shù)體,但是純虛析構(gòu)函數(shù)除外。
3. 重寫與重載
C++中用虛函數(shù)來實現(xiàn)多態(tài)機(jī)制,而Java中的類的方法都是隱式的虛函數(shù)。
重寫(覆蓋、override、overwrite)是子類和父類的變量名變量類型、方法名方法參數(shù)的類型個數(shù)順序完全一樣。
重載是函數(shù)名相同,參數(shù)類型、參數(shù)個數(shù)有一個不同,參數(shù)順序的差異可不可以構(gòu)成重載視情況而定,函數(shù)的返回值不同構(gòu)不成重載。
在子類中訪問父類被覆蓋的成員變量或方法,Java用super,C#用base,C++用作用域運(yùn)算符::。
動態(tài)綁定的時候如果訪問成員變量的話,都是訪問父類引用(Java)或父類指針(C++)指向的父類的成員變量,C++和Java皆如此。
動態(tài)綁定的話只有存在重寫的情況才會調(diào)用子類的方法函數(shù),如果不存在重載就直接在父類中尋找,如果找不到就報錯。
如下面的例子:輸出 ?”father“。
Java中可以有所謂的”跨類重載“,但是C++中卻不允許,具體可以參考這篇博文:http://blog.csdn.net/anialy/article/details/7621619。
而C++中肯定也有可以突破這種限制的方法,見這里:http://blog.csdn.net/autumn20080101/article/details/8514813。
關(guān)于C++的虛函數(shù)與重寫,我覺得這篇文章講的很好:C++的虛函數(shù)與重寫。
4. Java/C++中的hash_map/unordered_map的實現(xiàn)原理。
其實就是一個哈希函數(shù),配合數(shù)組和鏈表實現(xiàn),會存在數(shù)組的重新動態(tài)分配的過程。
5. 對Java多態(tài)的再思考
首先子類會繼承父類的所有成員變量和方法,即使是父類中的private部分,這是Java和C++肯定沒錯的地方。
從這個意義上來講,以前想過的對象初始化問題,其實就相當(dāng)于“子類自己對象的初始化”,而外在表現(xiàn)形式上看起來像先父類后子類等等那些初始化順序。
然后就是多態(tài)是基于重寫的,實際上仔細(xì)想想,如果在子類中重寫父類方法的話,因為肯定已經(jīng)繼承父類的方法,所以相當(dāng)于在子類里面有兩個“一模一樣”的函數(shù),
但是,在面向?qū)ο蟮倪^程中,這是允許的,這叫做重寫(覆蓋,override,overwrite),繼承的父類的函數(shù)會被隱藏掉。
而正確調(diào)用對應(yīng)的函數(shù)無疑依賴于多態(tài)由機(jī)制原理上的實現(xiàn),看來了解C++的虛函數(shù)表等底層一點的知識還是極其有必要。
6. C++中的using聲明
using聲明用于將變量或函數(shù)引入某一個空間,使其由不可見變?yōu)榭梢姞顟B(tài)。
聯(lián)想到上面提到的子類重載繼承的父類的函數(shù),在C++中子類再想調(diào)用重載過的父類的函數(shù),就必須用using聲明將其引進(jìn)來。
而Java中,在子類中繼承的父類的函數(shù)即使被重載過還是可見的,只有在被重寫的情況下才會失去其可見性。
有點令人意外的是,在C++中,子類中,using聲明可以引入被重寫過的父類的函數(shù),雖然這樣做沒有任何卵用,這個父類的函數(shù)依舊是不可見的。
其實這是合乎理的做法,你既然已經(jīng)重寫了父類的函數(shù),就已經(jīng)視為你在子類的作用域中不再需要這個父類的這個函數(shù),所以即使你強(qiáng)行引入,依舊是不可見的。
需要注意的是,using聲明在哪個訪問權(quán)限下會決定該變量或函數(shù)的訪問權(quán)限問題。
而且,C++11新標(biāo)準(zhǔn)下,引入了一個新的語法糖,姑且稱為“繼承的構(gòu)造函數(shù)”,當(dāng)然是加引號的。
用using聲明來在子類中引入父類中眾多的構(gòu)造函數(shù),相當(dāng)于實現(xiàn)“透傳”,這個using聲明的主要作用是令編譯器產(chǎn)生子類的構(gòu)造函數(shù)代碼。
using用于父類的構(gòu)造函數(shù)還有很多和通常的using不同之處,比如不會改變訪問權(quán)限,比如不會引入默認(rèn)、拷貝、移動構(gòu)造函數(shù)。
詳細(xì)的說明和例子在C++ primer中。
個人感覺這就是一個很甜的語法糖。
7. Java中子類對基類的方法進(jìn)行重寫時,不能具有比父類更嚴(yán)格的訪問權(quán)限,而C++中卻無此規(guī)定。
轉(zhuǎn)載于:https://www.cnblogs.com/niuxichuan/p/5854761.html
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的Java基础以及与C++的一些对比的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux_磁盘管理
- 下一篇: 免费开源分布式系统日志收集框架 Exce