參考鏈接: Java中的final數組 | Final arrays
1、final變量?
final關鍵字可用于變量聲明,一旦該變量被設定,就不可以再改變該變量的值。通常,由final定義的變量為常量。例如,在類中定義PI值,可以使用如下語句:?
final double PI=3.14;?
在Java中定義全局常量,通常使用public static final修飾,這樣的常量只能在定義是被賦值。?
public static final double PI_VAULE = 3.14;?
規范:被定義為final的常量定義時需要使用大寫字母命名,并且中間使用下劃線進行連接。?
常量示例:?
import java.util.Random;
?
class Test
{
? ? int i = 0;
}
?
/**
?* 常量示例
?*?
?* @author pan_junbiao
?*
?*/
public class FinalData
{
? ? static Random rand = new Random();
? ? private final int VALUE_1 = 9; // 聲明一個final常量
? ? private static final int VALUE_2 = 10; // 聲明一個final、static常量
? ? private final Test test = new Test(); // 聲明一個final引用
? ? private Test test2 = new Test(); // 聲明一個不是final的引用
? ? private final int[] a = { 1, 2, 3, 4, 5, 6 }; // 聲明一個定義為final的數組
? ? private final int i4 = rand.nextInt(20);
? ? private static final int i5 = rand.nextInt(20);
?
? ? public String toString()
? ? {
? ? ? ? return "i4值:" + i4 + " i5值:" + i5 + " ";
? ? }
?
? ? public static void main(String[] args)
? ? {
? ? ? ? FinalData data = new FinalData();
?
? ? ? ? // 報錯:不能改變定義為final的常量值
? ? ? ? // data.VALUE_1 = 8;
?
? ? ? ? // 報錯:不能改變定義為final的常量值
? ? ? ? // data.VALUE_2 = 9;
?
? ? ? ? // 報錯:不能將定義為final的引用指向其他引用
? ? ? ? // data.test = new Test();
?
? ? ? ? // 正確: 可以對指定為final的引用中的成員變量賦值
? ? ? ? data.test.i = 1;
?
? ? ? ? // 正確: 可以將沒有定義為final的引用指向其他引用
? ? ? ? data.test2 = new Test();
?
? ? ? ? // 報錯:不能對定義為final的數組賦值
? ? ? ? // int b[] = { 7, 8, 9 };
? ? ? ? // data.a = b;
?
? ? ? ? // 但是final的數組中的每一項內容是可以改變的
? ? ? ? for (int i = 0; i < data.a.length; i++)
? ? ? ? {
? ? ? ? ? ? data.a[i] = 9;
? ? ? ? }
?
? ? ? ? System.out.println(data);
? ? ? ? System.out.println("data2");
? ? ? ? System.out.println(new FinalData());
? ? }
}?
執行結果:?
??
從上述執行結果中可以發現i5的值是相同的。?
全局常量:?
我們知道一個被定義為final的對象引用只能指向唯一一個對象,不可以將它再指向其它對象,但是一個對象的值卻是可以改變的,那么為了使一個常量真正做到不可更改,可以將常量聲明為static final。?
示例:在項目中創建FinalStaticData類,在該類中創建Random類的對象,在主方法中分別輸出類中定義的final變量a1與a2。?
import static java.lang.System.out;
?
import java.util.Random;
?
/**
?* FinalStaticData類
?*?
?* @author pan_junbiao
?*
?*/
public class FinalStaticData
{
? ? private static Random rand = new Random(); // 實例化一個Random類對象
? ? // 隨機產生0~10之間的隨機數賦予定義為final的a1
? ? private final int a1 = rand.nextInt(10);
? ? // 隨機產生0~10之間的隨機數賦予定義為static final的a2
? ? private static final int a2 = rand.nextInt(10);
?
? ? public static void main(String[] args)
? ? {
? ? ? ? FinalStaticData fdata = new FinalStaticData(); // 實例化一個對象
? ? ? ? // 調用定義為final的a1
? ? ? ? out.println("重新實例化對象調用a1的值:" + fdata.a1);
? ? ? ? // 調用定義為static final的a2
? ? ? ? out.println("重新實例化對象調用a2的值:" + fdata.a2);
? ? ? ? // 實例化另外一個對象
? ? ? ? FinalStaticData fdata2 = new FinalStaticData();
? ? ? ? out.println("重新實例化對象調用a1的值:" + fdata2.a1);
? ? ? ? out.println("重新實例化對象調用a2的值:" + fdata2.a2);
? ? }
}?
運行結果:?
??
從本示例運行結果中可以看出,定義為final的常量不是恒定不變的,將隨機數賦予定義為final的常量,可以做到每次運行程序時改變a1的值。但是a2與a1不同,由于它被聲明為static final形式,所以在內存中為a2開辟了一個恒定不變的區域,當再次實例化一個FinalStaticData對象時,仍然指向a2這塊內存區域,所以a2的值保存不變。a2是在裝載時被初始化,而不是每次創建新對象時被初始化;而a1會重新實例化對象時被更改。?
最后總結一下在程序中final數據可以出現的位置,如下程序。?
/**
?* 總結一下在程序中final數據可以出現的位置
?*?
?* @author pan_junbiao
?*
?*/
public class FinalDataTest
{
? ? // final成員變量不可更改
? ? final int VALUE_ONE = 6;
?
? ? // 在聲明final成員變量時沒有賦值,稱為空白final
? ? final int BLANK_FINALVAULE;
?
? ? // 在構造方法中為空白final賦值
? ? public FinalDataTest()
? ? {
? ? ? ? BLANK_FINALVAULE = 8;
? ? }
?
? ? // 設置final參數,不可以改變參數x的值
? ? int doIt(final int x)
? ? {
? ? ? ? return x + 1;
? ? }
?
? ? // 局部變量定義為final,不可以改變i的值
? ? void doSomething()
? ? {
? ? ? ? final int i = 7;
? ? }
}?
??
2、final方法?
首先,我們應該了解定義為final的方法不能被重寫。?
將方法定義為final類型可以防止任何子類修改該類的定義與實現方式,同時定義為final的方法執行效率要高于非final方法。在修飾權限中曾經提到過private修飾符,如果一個父類的某個方法被設置為private修飾符,子類將無法訪問該方法,自然無法覆蓋該方法,所以一個定義為private的方法隱式被指定為final類型,這樣無須將一個定義為private的方法再定義為final類型。?
語法:?
private final void test()
{
}?
??
3、final類?
定義為final的類不能被繼承。?
如果希望一個類不允許任何類繼承,并且不允許其他人對這個類有任何改動,可以將這個類設置為final形式。?
final類的語法如下:?
final 類名{}?
如果將某個類設置為final形式,則類中的所有方法都被隱式設置為final形式,但是final類中的成員變量可以被定義為final或非final形式。?
示例:在項目中創建FinalClass類,在類中定義doit()方法和變量a,實現在主方法中操作變量a自增。?
/**
?* 定義final類
?*?
?* @author pan_junbiao
?*
?*/
final class FinalClass
{
? ? int a = 3;
?
? ? void doit()
? ? {
? ? }
?
? ? public static void main(String args[])
? ? {
? ? ? ? FinalClass f = new FinalClass();
? ? ? ? f.a++;
? ? ? ? System.out.println(f.a); // 結果:4
? ? }
}?
??
4、總結?
下面總結了一些使用final關鍵字的好處:?
(1)final關鍵字提高了性能。JVM和Java應用都會緩存final變量。?
(2)final變量可以安全的在多線程環境下進行共享,而不需要額外的同步開銷。?
(3)使用final關鍵字,JVM會對方法、變量及類進行優化。?
不可變類:?
創建不可變類要使用final關鍵字。不可變類是指它的對象一旦被創建了就不能被更改了。String是不可變類的代表。不可變類有很多好處,譬如它們的對象是只讀的,可以在多線程環境下安全的共享,不用額外的同步開銷等等。?
關于final的重要知識點:?
(1)final關鍵字可以用于成員變量、本地變量、方法以及類。?
(2)final成員變量必須在聲明的時候初始化或者在構造器中初始化,否則就會報編譯錯誤。?
(3) 你不能夠對final變量再次賦值。?
(4)本地變量必須在聲明時賦值。?
(5)在匿名類中所有變量都必須是final變量。?
(6)final方法不能被重寫。?
(7)final類不能被繼承。?
(8)final關鍵字不同于finally關鍵字,后者用于異常處理。?
(9)final關鍵字容易與finalize()方法搞混,后者是在Object類中定義的方法,是在垃圾回收之前被JVM調用的方法。?
(10)接口中聲明的所有變量本身是final的。?
(11)final和abstract這兩個關鍵字是反相關的,final類就不可能是abstract的。?
(12)final方法在編譯階段綁定,稱為靜態綁定(static binding)。?
(13)沒有在聲明時初始化final變量的稱為空白final變量(blank final variable),它們必須在構造器中初始化,或者調用this()初始化。不這么做的話,編譯器會報錯“final變量(變量名)需要進行初始化”。?
(14)將類、方法、變量聲明為final能夠提高性能,這樣JVM就有機會進行估計,然后優化。?
(15)按照Java代碼慣例,final變量就是常量,而且通常常量名要大寫。