Java基礎: 關鍵字 final

來源:互聯網
上載者:User

1. 修飾變數

 該變數既可以是局部變數也可以是成員變數,final關鍵字修飾的成員變數即常量,可以被繼承或者覆蓋和隱藏!主要從以下兩方面來說明問題。

 <1> 修飾基礎資料型別 (Elementary Data Type)

 final修飾的該變數就是常量,一旦賦值不可以改變其值。

一般情況,final修飾成員變數的話與static結合,使該常量可以被類直接調用,而不必建立對象,節省空間的。再者,如果該常量中不含不確定因素,就稱之為編譯時間期常量,反之為運行期常量。編譯時間期常量被調用時不會載入該類。http://blog.csdn.net/AndroidBluetooth/archive/2011/05/30/6454135.aspx

 

注意:測試方法(main方法)寫在該類中會載入該類的,所以測試方法放在單獨一個類中。例子:

package mark.zhang;<br />public class Linux {<br />// 修飾成員變數<br />public static final String NAME = "LINUX";<br />static {<br />System.out.println("--Linux---靜態代碼塊");<br />}<br />{<br />System.out.println("--Linux---動態代碼塊");<br />}<br />public Linux() {<br />}<br />public void getName() {<br />// 修飾局部變數<br />final int i = 7;<br />}<br />}<br />class Test {<br />public static void main(String[] args) {<br />System.out.println(Linux.NAME);<br />}<br />} 

結果:

LINUX 

還有這樣一種情況,不想在聲明常量的時候,給其賦值,那麼怎麼辦?

我們知道,如果在聲明常量的同時不將其賦值,編譯器會給我們一個類似The blank final field NAME may not have been initialized的錯誤。

第一種辦法,在靜態代碼塊中給常量賦值。

package mark.zhang;<br />public class Linux {<br />// 修飾成員變數<br />public static final String NAME;<br />static {<br /> System.out.println("--Linux---靜態代碼塊");<br /> NAME = "LINUX";<br /> }<br />{<br /> System.out.println("--Linux---動態代碼塊");<br />}<br /> public Linux() {<br /> }<br />}<br />class Test {<br /> public static void main(String[] args) {<br /> System.out.println(Linux.NAME);<br /> }<br />} 

結果:

--Linux---靜態代碼塊<br />LINUX 

分析:由於NAME是含有不確定因素,所以會載入靜態代碼塊,從而將其初始化。

注意:動態代碼塊無法完成final變數的初始化

第二種方法,在構造方法中初始化

如果這樣做,那麼成員常量不可以被static修飾。

static無法修飾構造方法,因為構造方法是在建立對象時被調用的,而static修飾的,只會在載入該類時被載入一次。

package mark.zhang;<br />public class Linux {<br />// 修飾成員變數,這裡沒有static<br />public final String NAME;<br />static {<br />System.out.println("--Linux---靜態代碼塊");<br />}<br />{<br />System.out.println("--Linux---動態代碼塊");<br />}<br />public Linux() {<br />NAME = "LINUX";<br />}<br />}<br />class Test {<br />public static void main(String[] args) {<br />System.out.println(new Linux().NAME);<br />}<br />} 

結果:

--Linux---靜態代碼塊<br />--Linux---動態代碼塊<br />LINUX 

那麼,有人說了,現在只有一個構造方法,如果再加一個或者n個構造方法呢,難道還要初始化嗎???yes,恭喜你,答對了。必須的,否則你得到類似這樣一個錯誤:

The blank final field NAME may not have been initialized 

例子:

public Linux() {<br />NAME = "LINUX";<br />}<br />public Linux(String name) {<br />NAME = "LINUX--LINUX";<br />} 

所以,正常情況下,不會使用這種方式。

<2> 修飾參考型別資料

注意:數組也是參考型別。

final修飾的引用不變指的是它的棧記憶體位址不變,即永遠指向那個堆裡的對象,但是堆裡的對象(屬性)是可變的!

樣本:

package mark.zhang;<br />public class Linux {<br />private String name = "linux OS";<br />static {<br />System.out.println("--Linux---靜態代碼塊");<br />}<br />{<br />System.out.println("--Linux---動態代碼塊");<br />}<br />public Linux() {<br />}<br />public void setName(String name) {<br />this.name = name;<br />}<br />public String getName() {<br />return name;<br />}<br />} 

測試方法:

class Test {<br />public static void main(String[] args) {<br />final Linux linux = new Linux();<br />System.out.println("linux's name : " + linux.getName());<br />// error: The final local variable linux cannot be assigned. It must be<br />// blank and not using a compound assignment<br />// linux = new Linux();<br />}<br />} 

但是我們可以修改其屬性值。

class Test {<br />public static void main(String[] args) {<br />final Linux linux = new Linux();<br />System.out.println("before--" + "linux's name : " + linux.getName());<br />linux.setName("ubuntu10.10");<br />System.out.println("after--" + "linux's name : " + linux.getName());<br />}<br />} 

結果:

--Linux---靜態代碼塊<br />--Linux---動態代碼塊<br />before--linux's name : linux OS<br />after--linux's name : ubuntu10.10 

2. 修飾類

final關鍵字修飾的類,類中成員方法預設為final,無法被繼承!Java提供的包中,String類就是一個用關鍵字final修飾的類,所以其他類無法繼承他!但是final關鍵字修飾的類可以作為子類,即可以繼承其他類!

3. 修飾方法

final關鍵字修飾的方法,可以被繼承,但是不能被覆蓋!這樣可以保證代碼的安全性。

注意:final和static一樣不可以修飾構造方法。

package mark.zhang;<br />public class Linux {<br />static {<br />System.out.println("--Linux---靜態代碼塊");<br />}<br />{<br />System.out.println("--Linux---動態代碼塊");<br />}<br />public Linux() {<br />}<br />/**<br /> * final修飾的方法可以被子類繼承,但是不可以被子類重寫 子類中也不可以與同名的該方法<br /> */<br />public final void getInfo() {<br />System.out.println("linux2.38");<br />}<br />}<br />class Ubuntu extends Linux {<br />// 一下兩種方式均會包類似下面的錯誤<br />// Cannot override the final method from Linux<br />/*<br /> * public final void getInfo() { System.out.println("ubuntu10.10"); }<br /> */<br />/*<br /> * public void getInfo() { System.out.println("ubuntu10.10"); }<br /> */<br />}<br />class Test {<br />public static void main(String[] args) {<br />Ubuntu ubuntu = new Ubuntu();<br />// 可以繼承父類的final方法<br />ubuntu.getInfo();<br />}<br />}<br /> 

4. final與abstract

final修飾的類不可以被繼承,然而abstract修飾的類本意就是希望子類去繼承。所以,在Java中不允許final修飾abstract,無論是abstract方法還是abstract類。

如果你這樣子去修飾一個抽象類別的話:

final abstract class Ubuntu {<br />abstract void get();<br />} 

編譯器毫不客氣的給你一個錯誤資訊:

The class Ubuntu can be either abstract or final, not both 

同樣的道理,final也不可以修飾abstract方法,如:

abstract class Ubuntu {<br />final public abstract void get();<br />} 

錯誤:

The abstract method get in type Ubuntu can only set a visibility modifier, one of public or protected 

從這句話中我們也可以得出結論:抽象方法不可以是private的,可以是default或者public或者protected。因為private方法子類不可見,更無法繼承或者重寫。

 

5. final與介面

final不能修飾interface介面 

6. final與構造方法

 

final不可以修飾構造方法

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.