你總覺得你會了,事實上你僅僅是隻知其一;不知其二。html
final關鍵字可用於聲明屬性、方法、參數和類,分別表示屬性不可變、方法不可覆蓋、參數不可變和類不可以繼承。java
咱們來分別看看它的使用方法。c++
final關鍵字是一個比較簡單的知識點,因此這篇文章我寫的比較舒服,你看着也比較舒服。因爲,很是easy呀~安全
被final修飾的屬性不可變。這樣的不可變的屬性。咱們可以稱之爲「常量」。markdown
這樣的常量大致上有兩種表現形式。多線程
先來看如下的代碼:dom
public class FinalAttribute {
private final String attribute_a = "chengfan";
public void test(){
//attribute_a = "zhangbingxiao"; 不可以這樣寫
}
}
這是最主要的final屬性,在定義的時候初始化。並且在編譯期值就已經肯定,不能改動。ide
咱們再來看一種:函數
public class FinalAttributeB {
private final String attribute_b;
public FinalAttributeB(String attribute_b){
this.attribute_b = attribute_b;
}
public void test(){
//attribute_b = "zhangbingxiao";
}
public void test(String attribute_b){
//this.attribute_b = attribute_b;
}
}
這樣的final屬性在編譯期間是沒法肯定屬性值的。僅僅有執行的時候才幹夠肯定(經過構造器初始化屬性)。相同,屬性一經初始化後就不可以改變。因此如下的test方法都沒法改動final屬性。post
上一篇文章中,咱們講了代碼塊,那麼能不能使用代碼塊來初始化final屬性呢?答案固然是可以的:
public class FinalAttributeB {
private final String attribute_b;
{
attribute_b = "zhangbingxiao";
}
static {
//attribute_b = "zhangbingxiao";
}
// public FinalAttributeB(String attribute_b){
// this.attribute_b = attribute_b;
// }
}
經過構造代碼塊初始化final屬性也是可以的,但是這樣就不能再使用構造函數初始化了。因爲構造代碼塊先於構造函數執行。
而final屬性僅僅能且必須初始化一次。
你可能發現了,我寫了靜態代碼塊。但是凝視掉了。沒錯,因爲靜態代碼塊僅僅能初始化靜態屬性。咱們在文章最後再討論它。
這樣的不在定義時初始化,而使用構造函數初始化的,也稱爲空白final變量。它爲final在使用上提供了更大的靈活性。爲此,一個類中的final數據成員就可以實現依對象而有所不一樣,卻有保持其恆定不變的特徵。
那除了構造函數,有沒有別的方式也達到編譯時初始化呢?固然有。比方你使用Random來初始化:
private final int attribute_c = new Random().nextInt();
這樣你僅僅有在執行的時候,才知道屬性值是多少。
剛剛咱們研究的都是基本數據類型。那麼,引用數據類型呢?直接看代碼:
public class FinalAttributeC {
private final Person person = new Person("zhangbingxiao");
public void change(){
person.setName("chengfan");
System.out.println(person.getName());
}
//public void change(Person p){
//this.person = p;
//}
public static void main(String[] args) {
new FinalAttributeC().change();
}
}
//結果 : chengfan
凝視掉的代碼是會報錯的代碼,也就是說引用類型person是不可以被改動的。
從結果可以看出來,Person對象內部的屬性被改變了。
因此,對於引用類型來講,引用自己是不可以改變得,但是引用指向的對象是可以改變的。
引用存在於棧中,而對象存在於堆中。引用的值是對象在堆中的地址。
在本質上,final修飾的是引用,而不是對象。因此引用的那個地址不可以變,而和對象沒多大關係。
舉個簡單的樣例,一我的是一個對象,他會穿上衣。褲子,鞋子,這些事人這個對象的屬性。
而人的名字是引用。當你一輩子下來,名字肯定(引用肯定)。你可以隨便換衣服,但是你的名字仍是那個。
我就舉個樣例。別和我擡槓。
。什麼可以去更名字,重名啥的。。你理解了final引用類型這個知識就行了。
當一個方法聲明爲final時,該方法不能被不論什麼子類重寫。本類可以重載,但是子類可以使用這種方法。
public class FinalMethod {
public final void test(){
}
public void test(int i){
}
}
class Test extends FinalMethod{
//public void test(){} 不可以重寫
@Override
public void test(int i) {
super.test(i);
}
public void test(int i,int j) {
}
}
被final修飾的方法,不可以被重寫。但是不影響本類的重載以及重載函數的重寫。
這裏有一種稱爲內聯(inline)的機制,當調用一個被聲明爲final的方法時。直接將方法主體插入到調用處。而不是進行正常的方法調用(類似於c++的內聯)。這樣有利於提升程序的效率。
但是假設方法過於龐大。可能看不到內聯調用帶來的不論什麼性能提高。在近期的Java版本號中。不需要使用final方法進行這些優化了。
當一個方法的形參被final修飾的時候,這個參數在該方法內不可以被改動。
public class FinalParam {
public void test(final int a ){
//a = 10; 值不可以被改動
}
public void test(final Person p){
//p = new Person("zhangbingxiao"); 引用自己不可以被改動
p.setName("zhangbingxiao"); //引用所指向的對象可以被改動
}
}
對於引用數據類型的改動規則同final屬性同樣。
final修飾參數在內部類中是很是實用的,在匿名內部類中,爲了保持參數的一致性。若所在的方法的形參需要被內部類裏面使用時,該形參必須爲final。
這個知識會在解說內部類的時候進行具體的討論,感興趣的可以先自行研究。
final修飾局部變量時僅僅能初始化(賦值)一次。可以不立刻初始化。
public class StaticPartAttr {
public void test(){
final int a ;
final int b = 2;
a = 3;
//a = 4; 報錯
//b = 5; 報錯
}
}
被final修飾的局部變量,僅僅能賦值一次。
你也可以一直不初始化。但是不不賦值,定義這個變量還有什麼用呢?
被final修飾的類不可以被繼承。所有方法不能被重寫(廢話,都不能繼承了,哪來的重寫)。但是這並不表示類內部的屬性也是不可改動的,除非這個屬性也被final修飾。這點在jdk裏有很是多應用,比方咱們熟知的String,Integer等類都被final修飾。
final類有很是多優勢,譬如它們的對象是僅僅讀的,可以在多線程環境下安全的共享。不用額外的同步開銷等等。
怎樣寫一個不可變類呢?
詳情—>丟個連接趕忙跑。
值得注意的是。一個類不可以既被abstract修飾又被final修飾。因爲final類不可以被繼承,而abstract類需要被繼承。關於抽象類。咱們會在下篇文章中具體解說。
當final和static同一時候使用的時候,咱們所熟知的「全局常量」就出現了:一個可以處處使用並且不可以改變的屬性,比方咱們熟知的Math.PI。Math.E。
上面咱們說到了靜態代碼塊初始化final變量的問題。
public class FinalStatic {
private final static double PI = 3.14;
private final static double E;
private final static double C ; //這裏會報錯
static {
E = 2.71;
}
public FinalStatic(double c){
C = c;
//PI = C; 這裏會報錯
}
}
對於靜態final變量,咱們可以直接初始化,或者使用靜態代碼塊。
而不可以使用構造函數或者構造代碼塊。
因爲static要求在編譯期間就肯定值,而後放入靜態區。
而構造函數和構造代碼塊發生在執行期間。因此不存在空白靜態final。
類中所有的private方法都隱式的指定爲final的,因爲沒法取用private方法,因此也就沒法覆蓋它。可以對private方法加入final修飾符,但並無加入不論什麼額外意義。
關於final的重要知識點
本文內容到此結束。假設文章有錯誤或者你有更好的理解方式,請及時與我聯繫~歡迎指出錯誤,比較我也是個學習的人而不是大神。
轉載請註明出處
本文地址:http://blog.csdn.net/qq_31655965/article/details/54800523
看完了,點個讚唄~