Java語言中的final關鍵字,想必你們都不是很陌生,咱們本身用的最多的應該是用來定義常量吧,那麼今天咱們就來了解final這個關鍵字的用法,這個關鍵字仍是很是簡單的。html
final從字面意思是不可更改的,最終的意思,它能夠用來修飾類、方法、變量(包括成員變量和局部變量)、參數。優化
final修飾類,表示該類不能再被繼承了,若是一個類它的功能比較完整,不須要擴展功能,咱們就可使用final來修飾。咱們最經常使用String、Integer、System等類就是用final修飾的,其不能再被其餘類所繼承。this
用final修飾類若是被繼承了那麼在編譯的時候就會報錯。spa
final修飾方法,表示這個方法不能被子類方法重寫。若是你認爲一個方法的功能已經足夠完整了,不須要再去子類中擴展的話,咱們能夠聲明此方法爲final。好比Object類中getClass()方法就是final修飾的。code
注意:類中全部的private方法都自動成爲final。因爲不能訪問一個private方法,因此它絕對不會被覆蓋。htm
final修飾變量表示是常量,通常都和static一塊兒使用,用來定義全局常量。final不管修飾的是成員變量仍是局部變量,都必須進行顯式初始化,以下。對象
1 public class FinalTest { 2 //顯式初始化 3 final int AA=11; 4 final int BB; 5 final int CC; 6 final int DD; 7 //構造代碼塊初始化 8 { 9 BB=22; 10 } 11 //構造方法初始化 12 public FinalTest(){ 13 CC=33; 14 DD=44; 15 } 16 17 public FinalTest(int CC, int DD) { 18 this.CC = CC; 19 this.DD = DD; 20 } 21 }
咱們能夠經過顯式初始化、構造代碼塊初始化、構造方法初始化這三種方式對final修飾的變量進行初始化。blog
前面都是講的final修飾基本數據類型的變量,若是final修飾引用變量會是怎麼樣,咱們來看一下舉例:繼承
1 public class FinalTest { 2 3 public static void main(String[] args) { 4 final AA aa = new AA(); 5 //這裏在引用其餘的對象就會報錯Cannot assign a value to final variable 'aa' 6 //aa=new AA(); 7 aa.i++; 8 System.out.println(aa.i); 9 } 10 11 } 12 13 class AA{ 14 int i; 15 } 16 17 //運行結果:1
能夠看到,雖然咱們將引用變量用final修飾了,可是該對象的變量 i 咱們仍是能夠進行修改,而這個變量的引用不能再指向另外一個對象了。代表final修飾的是引用變量,就不能再指向其餘對象,可是若是該對象內的變量不是final修飾的,其變量的值是能夠進行修改的。get
final修飾參數準確的來講應該是修飾形參,代表該形參的值不能被修改。
1 public class FinalTest { 2 3 public static void main(String[] args) { 4 FinalTest f=new FinalTest(); 5 f.show(5); 6 } 7 8 public void show(final int param){ 9 //編譯報錯:Cannot assign a value to final variable 'param' 10 //param=10; 11 System.out.println(param); 12 } 13 }
我在使用final修飾形參時,代表此形參是一個常量。當咱們調用方法的時候,給形參進行賦值,一旦賦值之後,就只能在該方法使用,並且不能進行從新賦值操做,不然編譯報錯。若是形參是引用類型,則引用變量不能再指向其餘對象,可是該對象的內容是能夠改變的。
參考連接:http://www.javashuo.com/article/p-heipsycl-n.html
當用final做用於類的成員變量時,成員變量(注意是類的成員變量,局部變量只須要保證在使用以前被初始化賦值便可)必須在定義時或者構造器中進行初始化賦值,並且final變量一旦被初始化賦值以後,就不能再被賦值了。那麼final變量和普通變量到底有何區別呢?下面請看一個例子:
1 public class Test { 2 public static void main(String[] args) { 3 String a = "hello2"; 4 final String b = "hello"; 5 String d = "hello"; 6 String c = b + 2; 7 String e = d + 2; 8 System.out.println((a == c)); 9 System.out.println((a == e)); 10 } 11 }
輸出結果:true、false
你們能夠先想一下這道題的輸出結果。爲何第一個比較結果爲true,而第二個比較結果爲fasle。這裏面就是final變量和普通變量的區別了,當final變量是基本數據類型以及String類型時,若是在編譯期間能知道它的確切值,則編譯器會把它當作編譯期常量使用。也就是說在用到該final變量的地方,至關於直接訪問的這個常量,不須要在運行時肯定。這種和C語言中的宏替換有點像。所以在上面的一段代碼中,因爲變量b被final修飾,所以會被當作編譯器常量,因此在使用到b的地方會直接將變量b 替換爲它的值。而對於變量d的訪問卻須要在運行時經過連接來進行。想必其中的區別你們應該明白了,不過要注意,只有在編譯期間能確切知道final變量值的狀況下,編譯器纔會進行這樣的優化,好比下面的這段代碼就不會進行優化:
1 public class Test { 2 public static void main(String[] args) { 3 String a = "hello2"; 4 final String b = getHello(); 5 String c = b + 2; 6 System.out.println((a == c)); 7 8 } 9 10 public static String getHello() { 11 return "hello"; 12 } 13 }
這段代碼的輸出結果爲false。這裏要注意一點就是:不要覺得某些數據是final就能夠在編譯期知道其值,經過變量b咱們就知道了,在這裏是使用getHello()方法對其進行初始化,他要在運行期才能知道其值。