[JAVA] Java面向?qū)ο笾甪inal、abstract抽象西轩、和變量生命周期

Java面向?qū)ο笾甪inal员舵、abstract抽象、和變量生命周期


final修飾符

final是最終藕畔、不可修改的意思马僻, 在Java中它可以修飾非抽象類,非抽象方法和變量注服。但是需要注意的是:構(gòu)造方法不能使用final修飾韭邓,因為構(gòu)造方法不能夠被繼承。下面溶弟,咱們就來一一看看吧女淑!

使用final關(guān)鍵字修飾類

先考慮下圖的代碼例子:

final class


代碼顯示錯誤,無法從SuperClass繼承可很,編譯器提示刪除final關(guān)鍵字诗力;刪除final關(guān)鍵字后,代碼正確無誤我抠。

代碼正確無誤


由此可得出:final修飾的類:苇本,表示最終的類,,即該類不能再有子類菜拓,不能再被繼承瓣窄。只要滿足以下條件就可以考慮把一個類設(shè)計成final類:

1. 在設(shè)計之初就考慮不進入繼承體系的類。

2. 出于安全考慮纳鼎,類的實現(xiàn)細節(jié)不允許被拓展和修改俺夕。比如:基本數(shù)據(jù)類型的包裝類就是一個典型的例子。

3. 該類不會再被拓展贱鄙。

java里final修飾的類有很多劝贸,比如八大基本數(shù)據(jù)類型的包裝類(Byte,Character逗宁、Short映九、Integer、Long瞎颗、Float件甥、Double捌议、Boolean)和String等。

Java 中的部分final類

使用final關(guān)鍵字修飾方法

如果用final關(guān)鍵字修飾方法呢引有?先考慮以下的代碼:

final 方法

若是用final修飾方法瓣颅,繼承該方法時會報編譯錯誤;刪除該關(guān)鍵字后譬正,doWork()可被繼承宫补,代碼編譯通過;final修飾的方法為最終的方法导帝,該方法不能被子類覆蓋守谓,故也不能使用方法重寫。那么什么樣的情況下方法需要使用final修飾呢您单?

1. 在父類中提供了統(tǒng)一的算法骨架斋荞,不允許子類通過方法覆蓋來修改其實現(xiàn)細節(jié), 此時使用final修飾虐秦。比如在模板方法設(shè)計模式中平酿。

2. 在構(gòu)造器中調(diào)用的方法(初始化方法),此時一般使用final修飾悦陋。這也是構(gòu)造器不能被繼承的原因蜈彼。

注意: final修飾的方法了,子類可以調(diào)用俺驶,但是不能覆蓋(重寫)幸逆。


類常量:使用final關(guān)鍵字修飾的字段

常量分類:

1. 字面值常量(直接給出的數(shù)據(jù)值/直接量);比如:整數(shù)常量1暮现,2还绘,3,小數(shù)常量3.14栖袋,布爾常量false拍顷,true等。

2. final關(guān)鍵字修飾的常量塘幅。

final關(guān)鍵字修飾的常量

通過上述代碼昔案,不難看出,final關(guān)鍵字修飾的字段無法被修改电媳。通常開發(fā)中踏揣,我們建議final修飾的常量名用大寫字母表示,多個單詞之間使用下劃線(_)連接:如:

final關(guān)鍵字修飾的字段

且在Java中多個修飾符之間的順序是沒有先后關(guān)系的匾乓,以下的三種修飾符排列順序都是ok的:

多個修飾符之間是沒有先后關(guān)系

final修飾的變量是最終的變量呼伸,常量;該變量只能賦值一次钝尸,也只能在聲明時被初始化一次括享,不能被修改。在使用時需注意:

1. final變量必須顯式地指定初始值珍促,系統(tǒng)不會為final字段初始化铃辖。

2. final變量一旦賦予初始值,就不能再被重新賦值猪叙。

3. 常量名規(guī)范:常量名符合標識符娇斩,單詞全部使用大寫字母,如果是多個單詞組成穴翩,多個單詞之間使用下劃線(_)連接犬第。全局靜態(tài)常量: public static final 修飾的變量,直接使用類名調(diào)用即可芒帕。

final修飾的引用類型變量到底表示引用的地址不能改變歉嗓,還是其存儲的數(shù)據(jù)不能改變

1. 修飾基本類型變量:表示該變量的值不能改變,即不能用“=”號重新賦值背蟆。

2. 修飾引用類型變量:表示該變量的引用的地址不能變鉴分,而不是其存儲的數(shù)據(jù)內(nèi)容不能變,其存儲的數(shù)據(jù)內(nèi)容是可以被修改的带膀。

什么時候使用常量

1. 當(dāng)在程序中志珍,多個地方使用到共同的數(shù)據(jù),而且該數(shù)據(jù)不會改變垛叨,此時可以將其定義全局的常量伦糯;

2. 一般的,在開發(fā)中我們會專門定義一個常量類嗽元,專門用來存儲常量數(shù)據(jù)敛纲。

為何要使用final修飾符呢?在繼承關(guān)系中最大弊端就是會破壞封裝还棱,子類能訪問父類的實現(xiàn)細節(jié),载慈,而且可以通過方法重寫(方法覆蓋)的方式修改方法的實現(xiàn)細節(jié)。且 final還是是唯一可以修飾局部變量的修飾符珍手。


抽象方法和抽象類

考慮以下的案例:求圓(Circle)办铡、矩形(rectangle)的面積

求圓(Circle)、矩形(rectangle)的面積 初始代碼設(shè)計


上述代碼設(shè)計是存在問題的:

1. 每一個圖形都有面積琳要。但是不同圖形求面積的算法是不一樣的寡具,也就是說,每一個圖形的子類都必須去重寫getArea方法稚补,如果不覆蓋童叠,應(yīng)該編譯報錯,無法計算其面積。

2. 在圖形類(Graph)中定義了getArea方法厦坛,該方法不應(yīng)該存在方法體五垮,因為不同圖形子類求面積算法不一樣,父類是不存在計算面積的方法的杜秸,故無法提供方法體放仗。

案例:求圓(Circle)、矩形(rectangle)的面積 引入抽象的設(shè)計


抽象方法

1. 使用abstract關(guān)鍵字修飾且沒有方法體的方法撬碟,稱為抽象方法诞挨。其特點是:

2. 使用抽象abstract關(guān)鍵字修飾,方法沒有方法體呢蛤,留給子類去實現(xiàn)/覆蓋其實現(xiàn)細節(jié)惶傻。

3. 抽象方法修飾符不能是private 和 final以及static,因為抽象方法是要被重寫的其障;

4. 抽象方法必須定義在抽象類或接口中银室。接口中的方法魔人都是使用public abstract 修飾的;

5. 一般會把abstract寫在方法修飾符最前面静秆,一看就知道是抽象方法粮揉;當(dāng)然如果不這樣寫也沒錯。

抽象類

使用abstract關(guān)鍵字修飾的類抚笔,稱為抽象類扶认。其特點是:

1. 抽象類不能創(chuàng)建實例,也就是不能使用new創(chuàng)建一個抽象類對象殊橙,即使創(chuàng)建出抽象類對象辐宾,調(diào)用了抽象方法,也無法實現(xiàn)功能膨蛮,因為抽象方法沒有方法體叠纹。

2. 抽象類可以不包含抽象方法,倘若包含敞葛,哪怕是一個誉察,該類也必須作為抽象類,抽象類可以包含普通方法惹谐,可以給子類調(diào)用持偏;抽象類是有構(gòu)造器的,且其子類構(gòu)造器必須先調(diào)用父類構(gòu)造器氨肌。

3. 若子類沒有實現(xiàn)/覆蓋父類所有的抽象方法鸿秆,那么子類也得作為抽象類(抽象派生類)。

4. 構(gòu)造方法不能都定義成私有的怎囚,否則不能有子類卿叽,因為子類構(gòu)造器無法調(diào)用其構(gòu)造器(創(chuàng)建子類對象前先調(diào)用父類構(gòu)造方法)。

5. 抽象類不能使用final修飾,因為其必須有子類重寫其抽象方法考婴,抽象方法才能得以實現(xiàn)贩虾。

6. 抽象類是不完整的類,需作為父類蕉扮,由子類實現(xiàn)其功能細節(jié)整胃,功能才能得以實現(xiàn)。

抽象類在命名時喳钟,一般使用Abstract作為前綴,讓調(diào)用者見名知義在岂,看類名就知道其是抽象類奔则。抽象類中可以不存在抽象方法,這樣做雖然沒有太大的意義蔽午,但是可以防止外界創(chuàng)建其對象易茬,所以我們會發(fā)現(xiàn)有些工具類沒有抽象方法,但卻是使用abstract來修飾類的及老。普通類有的成員(方法抽莱、字段、構(gòu)造器)骄恶,抽象類本質(zhì)上也是一個類食铐,故其都有。抽象類不能創(chuàng)建對象僧鲁,但抽象類中是可以包含普通方法的虐呻。


變量生命周期

程序中的變量是用來存儲數(shù)據(jù)的,其又分為常量和變量兩種寞秃,關(guān)于變量的詳情可以查看我的另一篇文章:http://www.reibang.com/p/2fa5a158e752([JAVA] Java 變量斟叼、表達式和數(shù)據(jù)類型詳解)。

定義變量的語法:數(shù)據(jù)類型 變量名 = 值;

變量根據(jù)在類中定義位置的不同春寿,分成兩大類成員變量局部變量

成員變量

成員變量: 全局變量/字段(Field)朗涩,是定義在類中,方法作用域外的變量绑改;可以先使用后定義(使用在前谢床,定義在后)。

1. 類成員變量:使用static修飾的字段绢淀。

2. 實例成員變量:也稱為對象變量萤悴,即沒有使用static修飾的字段。

局部變量

局部變量:?變量除了成員變量皆的,其他都是局部變量覆履,主要體現(xiàn)在方法內(nèi),方法參數(shù),代碼塊內(nèi)硝全;局部變量必須先定義而后才能使用栖雾。局部變量的使用如下:

1. 方法內(nèi)部的變量。

2. 方法的形參伟众。

3. 代碼塊中的變量析藕,一對{}中的變量。

變量的初始值:變量只有在初始化后才會在內(nèi)存中開辟空間凳厢。

1. 成員變量: 默認是有初始值的账胧。

成員變量的初始值


2. 局部變量: 沒有初始值。所以必須先初始化才能使用先紫,而且其初始化是在方法執(zhí)行開始時才進行的治泥。

變量的作用域:變量根據(jù)定義的位置不同,也決定了各自的作用域是不同的遮精,最直觀的就是看變量所在的那對花括號{}居夹,也就是離得最近的那對{}。成員變量的作用域在整個類中都有效本冲。局部變量的作用域在開始定義的位置開始准脂,到緊跟著結(jié)束的花括號為止。

變量的生命周期

變量的作用域指的是變量的可使用的范圍檬洞,只有在這個范圍內(nèi)狸膏,程序代碼才能訪問它。當(dāng)一個變量被定義時疮胖,它的作用域就確定了环戈。變量的作用域決定了變量的生命周期,作用域不同澎灸,生命周期就不一樣院塞。

變量的生命周期指的是一個變量被創(chuàng)建并分配內(nèi)存空間開始,到該變量被銷毀并清除其所占內(nèi)存空間的過程性昭。

package 關(guān)鍵字

在開發(fā)中拦止,一個項目會有成百上千個Java文件,如果所有的Java文件都在一個目錄中糜颠,那么管理起來就會很痛苦汹族,很難想象這樣的項目會是什么樣子。在Java中其兴,引入了稱之為包(package)的概念顶瞒。即:關(guān)鍵字:package ,專門用來給當(dāng)前Java文件設(shè)置包名(也就是命名空間)元旬。其語法格式如下:

package 命名

必須把package語句作為Java文件中的第一行代碼榴徐,在所有代碼之前守问。

package 語句和java編譯

在編譯java文件時的編譯命令為:

編譯java文件時的編譯命令

如果此時Hello.java文件中沒有使用package語句,表示在當(dāng)前目錄中生成字節(jié)碼文件坑资。運行時也不需要考慮包名耗帕。

如果此時Hello.java文件中使用了package語句,此時表示在當(dāng)前目錄中先生成包名目錄袱贮,再在包名目錄中生成字節(jié)碼文件仿便。運行命令如下:

運行java字節(jié)碼文件的命令

package命名

1.包名的定義:自定義的包名不能以java開頭,會和java語言基礎(chǔ)類庫沖突攒巍。

????a. 包名必須遵循標識符規(guī)范/全部小寫嗽仪。

????b. 企業(yè)開發(fā)中,包名由公司域名倒寫來決定窑业。

????c. 如果域名是以數(shù)字開頭的钦幔,不符合規(guī)范,可以考慮使用下劃線_開頭常柄;但是在Android中,如果package中使用了_搀擂,則不能部署到模擬器上西潘。此時,我們也可以使用一個字母來代替_哨颂。

? ??d. package命名格式

package命名格式

2. package下的類名:

????a. 類的簡單名稱: PackageDemo.java

????b. 類的全限定名稱: com._520.hello.PackageDemo.java

3.建議:先定義package名稱喷市,再在定義的package內(nèi)定義類。

import 關(guān)鍵字

當(dāng)A類和B類不在同一個包中威恼,若A類需要使用到B類中的功能品姓,此時就得讓A類中去引入B類。使用import語句箫措,把某個包下的類導(dǎo)入到當(dāng)前類中腹备。

語法格式:

import 語法格式

引入后在當(dāng)前類中,只需要使用類的簡單名稱即可訪問斤蔓。如果我們需要引入包中的多個類植酥,我們還得使用多個import語句,要寫很多次弦牡;此時可以使用通配符(*)友驮。

1. import 類的全限定名; 只能導(dǎo)入某一個類。

2. import 包名.子包名.*; 表示會引入該包下的所有的在當(dāng)前文件中使用到的類驾锰。

3. import java.util.*; 表示導(dǎo)入java.util包下的所有類卸留。

注意:編譯器會默認導(dǎo)入java.lang包下的類,但是并不會導(dǎo)入java.lang的子包下的類椭豫。比如:java.lang.reflect.Method類耻瑟,此時我們也得使用import java.lang.reflect.Method旨指;來導(dǎo)入Method類。


靜態(tài)import

靜態(tài)import匆赃,靜態(tài)導(dǎo)入账嚎,是指將通過import static導(dǎo)入其他類的靜態(tài)成員。以下代碼實例:

靜態(tài)import 代碼案例

然后我們對StaticImportDemo反編譯调窍,觀察JVM是如何處理靜態(tài)導(dǎo)入的:

JVM是如何處理靜態(tài)導(dǎo)入

通過上述的反編譯代碼台谢,不難發(fā)現(xiàn),其實所謂的靜態(tài)導(dǎo)入也是一個語法糖/編譯器級別的新特性瞬项,其實在底層也是類名.靜態(tài)成員去訪問的蔗蹋。所以在企業(yè)項目開始中不建議使用靜態(tài)導(dǎo)入,容易引起字段名囱淋,方法名混淆猪杭,不利于項目維護。

字段不存在多態(tài)

通過對象調(diào)用字段妥衣,在編譯時期就已經(jīng)決定了調(diào)用哪一塊內(nèi)存空間的數(shù)據(jù)皂吮。所以字段不存在覆蓋的概念,也就是字段不會有多態(tài)特征税手,在運行時期體現(xiàn)的也會是子類特征蜂筹。

字段不存在多態(tài)

通過運行上述代碼,不難發(fā)現(xiàn)芦倒,當(dāng)子類和父類存在相同的字段的時候艺挪,無論修飾符是什么(即使是private),都會在各自的內(nèi)存空間中存儲數(shù)據(jù)兵扬,字段并沒有體現(xiàn)出多態(tài)麻裳;其實通過方法重寫?字面意思也能發(fā)現(xiàn)其是針對方法的。所以只有方法才有覆蓋的概念器钟,而字段并不會被覆蓋津坑。


代碼塊

什么是代碼塊:在類或者在方法中,直接使用"{}"括起來的一段代碼俱箱,表示一塊代碼區(qū)域国瓮,我們將其稱為代碼塊。代碼塊里變量屬于局部變量狞谱,只在自己所在的作用域(所在的{})內(nèi)有效乃摹。根據(jù)代碼塊定義的位置的不同,我們又分成三種形式:

1.局部代碼塊:直接定義在方法內(nèi)部的代碼塊;一般不會直接使用局部代碼塊跟衅,而是會結(jié)合if孵睬,while,for伶跷,try等關(guān)鍵字配合使用掰读,還有匿名內(nèi)部類秘狞,表示一塊代碼區(qū)域。示例如下:

局部代碼塊

2.初始化代碼塊(構(gòu)造代碼塊):定義在類中蹈集,每次創(chuàng)建對象的時候都會執(zhí)行烁试,并且是在構(gòu)造器調(diào)用之前先執(zhí)行本類中的初始化代碼塊。但其實JVM在處理初始化代碼塊時是將其移動到構(gòu)造器中的最前面拢肆,從而達到先執(zhí)行初始化代碼塊减响,再執(zhí)行構(gòu)造器的功能。

在實際開發(fā)中郭怪,很少使用初始化代碼塊支示;初始化操作會在構(gòu)造器中進行,如果做初始化操作的代碼比較復(fù)雜鄙才,可以另外定義一個方法做初始化操作颂鸿,然后再在構(gòu)造器中調(diào)用。

3.靜態(tài)代碼塊:使用static修飾的初始化代碼塊攒庵。格式如下:

靜態(tài)代碼塊語法

靜態(tài)代碼塊會在主方法(main方法)執(zhí)行之前執(zhí)行嘴纺,而且只執(zhí)行一次。在Java中浓冒,main方法是程序的入口颖医,靜態(tài)代碼塊優(yōu)先于main方法執(zhí)行;是因為靜態(tài)成員是隨著字節(jié)碼的加載而進入JVM中的裆蒸,但此時此時main方法還沒執(zhí)行,因為main方法需要JVM調(diào)用方能執(zhí)行糖驴。

以下是一個代碼塊的示例:

靜態(tài)代碼塊案例

其運行結(jié)果為:

靜態(tài)代碼塊案例 運行結(jié)果

不難發(fā)現(xiàn)僚祷,調(diào)用順序依次為:靜態(tài)代碼塊--》初始化代碼塊--》構(gòu)造器,且靜態(tài)代碼塊只執(zhí)行一次贮缕。然后再對上述示例代碼做反編譯:

靜態(tài)代碼塊案例 反編譯

通過反編譯結(jié)果辙谜,發(fā)現(xiàn)JVM在處理初始化代碼塊時是將初始化代碼塊的代碼移動到構(gòu)造器中的最前面,從而達到先執(zhí)行初始化代碼塊感昼,再執(zhí)行構(gòu)造器的功能装哆。

完結(jié)。老夫雖不正經(jīng)定嗓,但老夫一身的才華

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜕琴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宵溅,更是在濱河造成了極大的恐慌凌简,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恃逻,死亡現(xiàn)場離奇詭異雏搂,居然都是意外死亡藕施,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門凸郑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裳食,“玉大人,你說我怎么就攤上這事芙沥』寤觯” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵憨愉,是天一觀的道長烦绳。 經(jīng)常有香客問我,道長配紫,這世上最難降的妖魔是什么径密? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮躺孝,結(jié)果婚禮上享扔,老公的妹妹穿的比我還像新娘。我一直安慰自己植袍,他們只是感情好惧眠,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著于个,像睡著了一般氛魁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厅篓,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天秀存,我揣著相機與錄音,去河邊找鬼羽氮。 笑死或链,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的档押。 我是一名探鬼主播澳盐,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼令宿!你這毒婦竟也來了叼耙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤掀淘,失蹤者是張志新(化名)和其女友劉穎旬蟋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體革娄,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡倾贰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年冕碟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匆浙。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡安寺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出首尼,到底是詐尸還是另有隱情挑庶,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布软能,位于F島的核電站迎捺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏查排。R本人自食惡果不足惜凳枝,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跋核。 院中可真熱鬧岖瑰,春花似錦、人聲如沸砂代。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刻伊。三九已至露戒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捶箱,已是汗流浹背玫锋。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讼呢,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓谦炬,卻偏偏與公主長得像悦屏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子键思,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容