final
final修飾的範圍
區域中的變數、全域變數、類別、屬性、方法。
不能放在建構子前面。
final 常數
final放在變數前,代表變數的值不能被修改,而且一定要給預設值。
因為值不能被修改,所以不是變數,是常數。
1
2
3
final String msg = "Test";
// 下面會編譯錯誤
msg = "ABC";
參數x是final,但下面程式碼不會有錯誤,因為並沒有修改到x。
1
2
3
public int add(final int x) {
return x + 1;
}
若使用x++就會有錯誤,因為x++就是x = x + 1
,是修改x常數,但是final不能被修改。
1
2
3
4
5
public int add(final int x) {
//
x++;
return x + 1;
}
final與陣列
Prerequisites:
final對於陣列而言,變數是不能再指向其它陣列。
1
2
3
4
final char[] arr1 = {'H', 'e', 'l', 'l', 'o'};
char[] arr2 = {'W', 'o', 'r', 'l', 'd'};
// 下面會編譯錯誤,arr1不能再指向其它陣列。
arr1 = arr2;
但可以修改陣列裡的內容。
1
2
3
4
5
6
7
final char[] arr1 = {'H', 'e', 'l', 'l', 'o'};
arr1[0] = 'W';
arr1[1] = 'o';
arr1[2] = 'r';
arr1[3] = 'l';
arr1[4] = 'd';
System.out.println(arr1);
World
類別中的final
常數
final放在屬性前,就變成常數,因為不能再改變,而且一定要給預設值。
final常數,不能再被修改,繼承的子類別也不能修改final常數,本身類別也不能修改final常數,只被設定一次。
常數名為大寫,用底線作分隔,例如: IMG_PATH
1
2
3
public class Test {
public final String IMG_URL = "http://xxxxxxx";
}
在下面幾種情況,final可以不設預設值
不是static的final
final原本一定要設預設值。
1
public final String IMG_URL = "http://xxxxxxx";
下面的狀況下,可以不用設預設值。
在建構子中會設定final的值,final就可以不設預設值。
1
2
3
4
5
6
7
public class Test {
public final String IMG_URL;
public Test(String IMG_URL) {
this.IMG_URL = IMG_URL;
}
}
在匿名區塊會設定final的值,final就可以不設預設值。
1
2
3
4
5
6
7
public class Test {
public final String IMG_URL;
{
IMG_URL = "http://xxxxxx";
}
}
final static
final static 原本一定要設預設值。
1
public final static String IMG_URL = "http://xxxxxx";
在以下的狀況,可以不用設預設值。
在靜態區塊會設定final static的值,final static就可以不設預設值。
1
2
3
4
5
public class Test {
public final static String IMG_URL;
static {
IMG_URL = "http://xxxxxx";
}
final + static 不會呼叫靜態區塊
編譯器看到final static 基本型態,就會自動把它的值,取出來進行覆蓋。
1
2
3
4
5
6
7
8
9
10
11
public class Test {
public static void main(String[] args) {
System.out.println(WebSite.IMG_URL);
}
}
class WebSite {
public final static String IMG_URL = "http://xxxxxx";
static {
System.out.println("靜態區塊初始化");
}
}
編譯後,就會變成以下內容,所以執行這段程式碼根本看不到WebSite這個類別。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
// 原本是System.out.println(WebSite.IMG_URL);
System.out.println("http://xxxxxx");
}
}
http://xxxxxx
final 類別
為什麼會有final類別呢?有一些基礎的類別,不想再被人繼承,也不想被人覆寫方法。String、Double、Integer…都是final 類別。
不能被繼承
1
2
3
// 父類別不能被繼承
final class Parent {
}
子類別繼承final父類別,會編譯錯誤。
1
2
3
// 以下程式碼會編譯錯誤
class Child extends Parent {
}
可以建立物件
final Parent
1
2
final class Parent {
}
建立Parent物件。
1
2
3
4
5
public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
}
}
final類別中的方法不用寫final
因為final類別不能被繼承,不會有子類別,所以不可能有子類別覆寫父類別方法。
以下的寫法畫蛇添足。
1
2
3
4
final class Parent {
public final void method() {
}
}
final 方法
不能被子類別覆寫方法,但子類別可以使用父類別的方法。
父類別
1
2
3
4
5
class Parent {
public final void method() {
System.out.println("父類別方法1");
}
}
子類別嘗試覆寫method(),會編譯錯誤。
1
2
3
4
5
6
class Child extends Parent {
// 以下程式碼編譯錯誤
public final void method() {
System.out.println("子類別方法1");
}
}
子類別可以使用父類別方法。
1
2
3
4
5
6
class Child extends Parent {
public final void method1() {
// 使用父類別方法
super.method();
}
}