一、基本用法
** 1. 修飾類 **
當final修飾一個類時,表明這個類不能被繼承。final類中的成員變量可以根據需要設為final,注意:final類中的所有成員方法會被隱式的指定為final方法。
自己一般將util包和helper包下的類設為final。
** 2. 修飾方法 **
《Java編程思想》:
“使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實現版本中,會將final方法轉為內嵌調用。但是如果方法過于龐大,可能看不到內嵌調用帶來的任何性能提升。在最近的Java版本中,不需要使用final方法進行這些優化了。“
因此,如果只有在想明確禁止 該方法在子類中被覆蓋的情況下才將方法設置為final的。
注:類的private方法會隱式地被指定為final方法。
** 3. 修飾變量 **
對于一個final變量,如果是基本數據類型的變量,則其數值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。
二、Q & A
** 1. 類的final變量和普通變量有什么區別 **
當用final作用于類的成員變量時,成員變量(注意是類的成員變量,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時或者構造器中進行初始化賦值,而且final變量一旦被初始化賦值之后,就不能再被賦值了。
** 2. 被final修飾的引用變量指向的對象內容可變嗎? **
引用變量被final修飾之后,雖然不能再指向其他對象,但是它指向的對象的內容是可變的。
** 3. final和static **
static作用于成員變量用來表示只保存一份副本,而final的作用是用來保證變量不可變。
public class Test {
public static void main(String[] args) {
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
System.out.println(myClass1.i);
System.out.println(myClass1.j);
System.out.println(myClass2.i);
System.out.println(myClass2.j);
}
}
class MyClass {
public final double i = Math.random();
public static double j = Math.random();
}
每次打印的兩個j值都是一樣的,而i的值卻是不同的。從這里就可以知道final和static變量的區別了。
** 5. final參數 **
使用final修飾方法參數的目的是防止修改這個參數的值,同時也是一種聲明和約定,強調這個參數是不可變的。
但是實際情況中,無論參數是基本數據類型的變量還是引用類型的變量,使用final聲明都不會達到上面所說的效果。
public class FinalTest {
public static void main(String[] args) {
A a = new A();
int i = 0;
a.increase(i);
}
}
class A {
void final increase(final int i) {
i++;
}
}
i++會報錯。不過,在方法內部改變i的值并不會影響方法外的i值,因為java采用值傳遞。
public class Test {
public static void main(String[] args) {
MyClass myClass = new MyClass();
StringBuffer buffer = new StringBuffer("hello");
myClass.changeValue(buffer);
System.out.println(buffer.toString());
}
}
class MyClass {
void changeValue(final StringBuffer buffer) {
buffer.append("world");
}
}
運行這段代碼就會發現輸出結果為 helloworld。很顯然,用final進行修飾并沒有阻止在changeValue中改變buffer指向的對象的內容。如把final去掉了,然后在changeValue中讓buffer指向了其他對象,也不會影響到main方法中的buffer,原因在于java采用的是值傳遞,對于引用變量,傳遞的是引用的值,也就是說讓實參和形參同時指向了同一個對象,因此讓形參重新指向另一個對象對實參并沒有任何影響。