final關鍵字/編譯時常量與運行時常量/繼承與初始化

final可以用來修飾數據、方法、類。

final數據

1、final修飾變量
final修飾基本數據類型的變量時,必須賦予初始值且不能被改變。
static final修飾的是常量,常量分爲編譯時常量與運行時常量,定義爲static,強調只有一份。
比如static final int a = 10;就是編譯時常量,只要是該常量帶入的語句,在編譯過後都會替換。
這段代碼
在這裏插入圖片描述
在反編譯後變成
在這裏插入圖片描述
而且只要這種常量在的算式,在編譯時期就會被計算。(只有基本數據類型和String)
在這裏插入圖片描述
反編譯後
在這裏插入圖片描述
很明顯了。
關於運行時常量:static final int a = “123”.length();就是一個運行時常量,它的賦值會引起類的初始化。
編譯器常量有一個風險。就比如A類定義了常量,B類使用了常量。但現在需要修改A類源碼的常量值,對A類重新編譯,但沒對B類重新編譯,這就導致A類與B類的常量值不一樣。
2、final修飾引用
對於對象引用,final使引用恆定不變。就是一旦引用指向一個對象,就無法把他再指向另一個對象,但對象是可以修改的。數組也一樣,畢竟數組也是對象。
3、空白final
所謂空白final就是被聲明爲final但未賦初值的域,但在使用前,必須保證賦初值,這樣就可以靈活的爲其進行賦值,但是又保持了其不可更改的特性 。
必須在域定義處(final修飾局部變量)或每個構造器裏(final修飾成員變量)用表達式對final進行賦值。

public class Tests {
	private final int j;
	public Tests(){
		j = 0;
	}
	public Tests(int x){
		j = x;
	}
	public static void main(String[] args) {
		new Tests(12);
		final int k;
		k = 2;
		System.out.println(k);
    }
}

3、final參數
被final修飾的參數稱位final參數。意思是你無法更改參數引用所指向的變量,可以讀參數,但不可修改參數。主要用於向內部類傳遞數據。
4、final方法
被final修飾的方法,只能被繼承,不能被覆蓋
final與private關鍵字:類中所有private方法都被隱式指定是final的,但如果在子類定義一個與父類方法名、參數列表、返回值都相同的private方法也可以,但調用的時候,還是按照private的法則,private方法只在本類中使用,而且用@Override也會報錯,也就是說父類與子類的相同的private方法沒有任何關係。
5、final類
當類被final修飾時,表示類是不可被繼承的。final類中的所有方法都是隱式的指定爲final的,無法被覆蓋。但成員變量不是final,你可以人爲指定某個成員變量是final。



繼承與初始化

如下代碼:

public class Battle extends Insect {
	private int k = printInit("Battle.k initialized");
	public Battle(){
		System.out.println("k = " + k);
		System.out.println("j = " + j);
	}
	private static int x2 = printInit("static Battle.x2 initialized");
	public static void main(String[] args) {
		System.out.println("Battle constructor");
		Battle t = new Battle();
    }
}
class Insect{
	private int i = 9;
	protected int j;
	Insect(){
		System.out.println("i = " + i + ", j = " + j);
		j = 39;
	}
	private static int x1 = printInit("static Insect.x1 initialized");
	static int printInit(String s){
		System.out.println(s);
		return 47;
	}
}

輸出
在這裏插入圖片描述
在Battle上運行Java時,程序想要訪問Battle類的main方法,這時加載器就要找出Battle的.class文件,對它進行加載。加載過程中,發現它有一個父類,於是就要對父類進行加載,如果發現父類還有父類,那就要加載“爺爺類”,不要認爲加載父類是由於本類調用了父類的靜態方法,實際上去掉調用父類的成員變量,父類還是先加載。
父類的static初始化完後,就輪到自己的static執行,執行完後,也就輸出了前兩行。
執行到這,說明必要的類已經加載完畢了。進入main方法,輸出Battle constructor。開始創建對象。先把對象內所有的基本類型設置爲默認值,引用類型設置爲null(通過將對象內存設爲二進制零值一舉生成的),然後,構造器開始調用,我們知道,子類構造器會默認在第一行添加super(),先調用父類構造器,輸出i = 9, j = 0;,然後子類構造器執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章